Well, ultimately it's a trade-off: adding new configuration options
inevitably makes code more complex and introduces new vectors for
bugs, so such things should be considered carefully against the fact
that it's pretty easy to write a ModelChoiceField subclass and
override the bit that spits out the choices.
--
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."
I am a +1 on a configuration parameter since the alternative by
subclassing is a bit too involved for something fairly trivial. See my
post about how to do so:
http://oebfare.com/blog/2008/feb/23/overriding-modelchoicefield-labels/
--
Brian Rosner
http://oebfare.com
I had to do this the other night, and it is sort of a pain in the ass.
I haven't looked at the proposed solution(s), but it seems like this
would be nicely solved by a callback that can be passed in to
ModelChoiceField's constructor. The callback would just be a function
that takes an item from the queryset, and spits out a choice tuple.
Another possibility could be to allow ModelChoiceField to take a
custom object in place of QuerySetIterator and possibly adding
something like an emit_choice(obj) method to it to make subclassing a
little easier.
As it stands right now, you have to override a method, redefine a
property (to make your new method work), and reimplement
QuerySetIteratior.
I'm not going to write the code or the tests, but I'd be happy to
provide feedback for someone who *is* willing. I'll also try to beat
the relevant objectors into submission. ;)
Joseph
And this is exactly what the patch for #4620 does. Sorry, next time
I'll be a good boy and know what I'm talking about. ;)
Joseph
I'm not too happy with the callback idea in the patch right now -- any
other good ideas?
Jacob
Had a quick chat with Joseph about this, and here's the idea I came up
with. Just a sketch, but if someone wants to run with it and see where
it goes that would be cool.
So I see no reason for QuerySetIterator to exist -- nothing uses it
except ModelChoiceField._get_choices, but because it's there you have
to subclass both ModelChoiceField and QuerySetIterator, and that's
lame.
So I think we should merge QuerySetIterator into
ModelChoiceField._get_choices. Once that's done, it's pretty trivial
to make _get_choices perform a callback to get the label for a
particular choice -- something like::
def _get_choices(self):
...
for obj in self.queryset:
yield (obj.ok, self.label_for_object(obj))
...
Then subclasses would just need to define label_for_object -- which,
BTW, is a really shitty name. Whoever paints this particular bikeshed
should be sure to choose another color.
Jacob
I was about 80% finished writing more or less the same solution over
here. Now I can save some typing and just say that I agree with you
guys. I got there via pretty much the same logic, too: subclassing
should be the solution, but it should require less keystrokes than it
does now.
Malcolm
--
Tolkien is hobbit-forming.
http://www.pointy-stick.com/blog/
If I can side-track the conversation for a moment and point to
something else I think should require a few less keystrokes to
subclass... The newforms widget render method.
Maybe I'm wrong, but it seems like all the attribute collecting could
be pushed into another method so that render() has a call to get_attrs
and simply returns the string. If I want to subclass widgets to make
HTML4 widgets (for example, in this snippet:
http://www.djangosnippets.org/snippets/618/), there are 4 lines of
code that are a straight cut and paste from the Input class' render()
method. (Or maybe there's a simpler way to do this?)
Thanks,
-Rob
Very much agree. +1
Gary
Please, don't -- start another thread.
Jacob
I wonder if this should be done in two methods so that iteration is
encapsulated away from queryset caching invalidation. Otherwise I am +1
on using subclassing to solve the problem.
>
>>
>> def _get_choices(self):
>> ...
>> for obj in self.queryset:
>> yield (obj.ok, self.label_for_object(obj))
>> ...
>
> I wonder if this should be done in two methods so that iteration is
> encapsulated away from queryset caching invalidation. Otherwise I am +1
> on using subclassing to solve the problem.
Ok, perhaps I should read the code before commenting. My bad :P