Define your model and form just like you normally would.
class Task(Model):
owner = models.ForeignKey(User)
status = models.IntegerField(choices=STATUS_CHOICES)
class TaskForm(ModelForm):
class Meta:
model = Task
Then in your view, create your choices and pass them to the form constructor.
choices = {
'owner': User.objects.filter(is_active=True),
'status': STATUS_CHOICES[1]
}
form = SomeForm(choices=choices)
Now your form *instance* has restricted choices, but your form *class*
is untouched, which is exactly what we want.
So that takes care of dynamic choices for forms, but what about
generic views and admin views? For the admin, use the same approach
discussed in #3987 [1]. We can do the same thing for generic views
once they are class based [2].
class SomeAdmin(ModelAdmin):
def choices_for_owner(self, request):
return User.objects.filter(is_active=True)
If we do the above, I think we can go ahead and close #2445 [3]. Are
there any other related tickets that I missed?
Joseph
[1] http://code.djangoproject.com/ticket/3987
[2] http://code.djangoproject.com/ticket/6735
[3] http://code.djangoproject.com/ticket/2445
This doesn't feel a lot less complicated than just assigned to the right
fields' self.field entry in the form's __init__ method. It might save
two lines of code when you use it (once, since you'll *reuse* the same
form base every other time), but everybody has to tolerate this extra
parameter floating around in the docs and in overridden calls, etc.
We switched from form_for_* to classes so that things could be
overridden and added to easily and now we're slipping more and more
stuff back into the form's __init__ method call to make it look more
like a function again.
Please make up your mind! :-)
[...]
> Now your form *instance* has restricted choices, but your form *class*
> is untouched, which is exactly what we want.
You mean the same as if it was done in the __init__() method of the form
subclass? :-)
I'm -0 (I'm actually minus a lot in reality, but there are more
important things to debate) on this because it feels like something
that's already not particularly difficult (could be documented and the
new stuff is going to need documentation anyway, so that's a wash) and
not being made amazingly easier in this fashion. Every time we add a
parameter to the __init__ call, it's one more parameter that you have to
look up how to use each time (it's even worse for parameters that take
large bags of goo like big dictionaries or "attrs").
I guess it will probably end up going in because people will quote
statistics about how 73.67% of all working parents use this in their
daily lives (without burdening us with the raw data they used to create
those statistics). But it's not adding something that can't already be
done very easily. It's not even repetitive. If your app needs to do this
a lot, you have a form base class that does it, which you write exactly
once to suit your needs. Where do you draw the line here? At 5 extra
parameters to support "things that more than one person does"? 10?
Malcolm
I have to say I'm with Malcolm on this one. I can see what you're
trying to do, but an argument to __init__ doesn't seem like the right
place to do it.
> Now your form *instance* has restricted choices, but your form *class*
> is untouched, which is exactly what we want.
Is it? I can't say I have any particular form class defining a set of
rules for the allowed choices, as long as there is flexibility to
define the specific parameters on a per-instance basis. For example,
consider the case where a ForeignKey(User) must take a currently
active user, and the email address must match a argument provided on a
per-instance basis. The is_active filter is constant across the class,
as is the email__icontains=XXX; however, the value XXX per form
instance.
> So that takes care of dynamic choices for forms, but what about
> generic views and admin views? For the admin, use the same approach
> discussed in #3987 [1]. We can do the same thing for generic views
> once they are class based [2].
>
> class SomeAdmin(ModelAdmin):
> def choices_for_owner(self, request):
> return User.objects.filter(is_active=True)
This general approach seems much more helpful, although ultimately I
don't see it as being that far removed from the original proposal in
#2445. Picking a 'choices_for_*' convention for a form method is
essentially no different to allowing a callable argument to
limit_choices_to that requires a particular prototype; as far as
nomenclatures go, both have benefits, but the fact that the
choices_for_ syntax can also be used for ModelAdmin (a la #3987) is a
particularly good bonus.
Yours,
Russ Magee %-)