I have a Django my_forms.py like this:
class CarSearchForm(forms.Form):
# lots of fields like this
bodystyle = forms.ChoiceField(choices=bodystyle_choices())
Each choice is e.g. ("Saloon", "Saloon (15 cars)"). So the choices are computed by this function.
def bodystyle_choices():
return [(bodystyle.bodystyle_name, '%s (%s cars)' %
(bodystyle.bodystyle_name, bodystyle.car_set.count()))
for bodystyle in Bodystyle.objects.all()]
My problem is the choices functions are getting executed every time I merely import my_forms.py. I think this is due to the way Django declares its fields: in the class but not in a class method. Which is fine but my views.py imports my_forms.py so the choices lookups are done on every request no matter which view is used.
I thought that maybe putting choices=bodystyle_choices with no bracket would work, but I get:
'function' object is not iterable
Obviously I can use caching and put the "import my_forms" just in the view functions required but that doesn't change the main point: my choices need to be lazy!
-
Try using a ModelChoiceField instead of a simple ChoiceField. I think you will be able to achieve what you want by tweaking your models a bit. Take a look at the docs for more.
I would also add that ModelChoiceFields are
lazy
by default :) -
Another solution is to move the
bodystyle
field to the class constructor:class CarSearchForm(forms.Form): def __init__(self, *args, **kwargs): super(CarSearchForm, self).__init__(*args, **kwargs) self.fields['bodystyle'] = forms.ChoiceField(choices=bodystyle_choices())
Tom Viner : I think I will keep the class definition part, but have self.fields['bodystyle'].choices = bodystyle_choices() in the constructor. -
You can use the "lazy" function :)
from django.utils.functional import lazy class CarSearchForm(forms.Form): # lots of fields like this bodystyle = forms.ChoiceField(choices=lazy(bodystyle_choices, tuple)())
very nice util function !
0 comments:
Post a Comment