Interaction between [Multiple]ModelChoiceField and its widget

336 views
Skip to first unread message

Arnaud Delobelle

unread,
May 29, 2008, 4:55:39 AM5/29/08
to Django developers
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/

Justin Bronn

unread,
May 29, 2008, 9:42:05 AM5/29/08
to Django developers
> 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.  

I totally agree. A common use case I've encountered when using the
admin (specifically, I'm using newforms-admin) is the ability to
override the Model[Multiple]Choice field to only display the related
objects associated with a given model in the admin. Otherwise, the
browser buckles under the pressure of having to populate a <select>
element with thousands of possibilities. I believe such a
customization hook would benefit newforms-admin, and as customization
hooks are currently being discussed in a separate thread [1] perhaps
it should be mentioned again there.

Now before someone comes saying "use raw_id_fields", they are
insufficient because they are, well, too "raw" -- forcing a client to
input integer ids is not my idea of user friendly. I had to come up
with my own form fields, widgets, and a `ModelAdmin` subclass to
accomplish the customization of the queryset displayed to the user
[2]. Much of the code would be unnecessary if it was possible to
easily override the queryset.

[1] Simon Willison, "newforms-admin customisation hook suggestions",
http://groups.google.com/group/django-developers/browse_thread/thread/53eaa25074ff4369
[2] http://geodjango.org/hg/limited_related/
Reply all
Reply to author
Forward
0 new messages