Hi,
I would like to suggest a modest change in some newforms objects,
namely ModelChoiceField and MultipleModelChoiceField, and how they
interact with their widgets. Before I describe the change, let me
explain an example in which I think this is desirable.
There is also the possibility that I have not understood newforms
correctly, in which case please forgive me!
== Example ==
I find it quite common to create a form with a
[Multiple]ModelChoiceField which I have to assign dyamically
(according to what choices are accessible to the current user, for
example).
Also, when the number of choices is big, none of the provided widgets
are very usable, so I have for instance created a TreeSelect widget
which groups choices into categories (columns in the table) and
displays them in a tree whose branches are collapsible (see an example
at [1]). But in order to do that, the widget needs to know its
field's queryset, not just its choices.
But as far as I can see, there is no builtin way, when you change the
queryset property of a [Multiple]ModelChoiceField, for this change to
propagate automatically to its widget. Instead a ModelChoiceIterator
is built from the queryset and is passed to the widget as its new
choices attribute.
For example, I have a form for creating a 'loop game':
class CustomLoopForm(forms.ModelForm):
questions = forms.ModelMultipleChoiceField(
None,
label="Questions",
widget=TreeSelect(grouper='category'))
Now when I build the form, the questions available depend on who is
logged in, so I have to do something like this
# Taylor available questions according to current user
avail_questions = Item.objects.visible_by(request.user)
loopform.fields['questions'].queryset = avail_questions
loopform.fields['questions'].widget.queryset = avail_questions
and repeat myself.
I think there should be a way for the 'questions' fields to propagate
its new queryset to its widget, just like a normal ChoiceField
propagates its new choices to its widget.
== What I would like ==
At the moment, in django.newforms.models.ModelChoiceField we have:
def _get_queryset(self):
return self._queryset
def _set_queryset(self, queryset):
self._queryset = queryset
self.widget.choices = self.choices
queryset = property(_get_queryset, _set_queryset)
This could be changed like this:
def _set_queryset(self, queryset):
self._queryset = queryset
if hasattr(self.widget, 'queryset'):
self.widget.queryset = queryset
if hasattr(self.widget, 'choices'):
self.widget.choices = self.choices
So that widgets that want to use extra information about the choices
(such as my TreeSelect widget) can be updated by their field
accordingly.
Another solution would be to let widgets have a 'field' attribute
telling them what field they are a widget for, but I don't know how
that would work as several fields can share the same widget.
-- Arnaud
[1]
http://www.marooned.org.uk/qmm/games/bingo/new/