2009-02-20 3 views
19

У меня есть Django my_forms.py вроде этого:Ленивые выбор в Django форме

class CarSearchForm(forms.Form): 
    # lots of fields like this 
    bodystyle = forms.ChoiceField(choices=bodystyle_choices()) 

Каждый выбор, например, («Салон», «Салон (15 автомобилей)»). Таким образом, выбор вычисляется с помощью этой функции.

def bodystyle_choices(): 
    return [(bodystyle.bodystyle_name, '%s (%s cars)' % 
      (bodystyle.bodystyle_name, bodystyle.car_set.count())) 
      for bodystyle in Bodystyle.objects.all()] 

Моя проблема в том, что функции выбора выполняются каждый раз, когда я просто импортирую my_forms.py. Я думаю, это связано с тем, как Django объявляет свои поля: в классе, но не в методе класса. Это нормально, но мой view.py импортирует my_forms.py, поэтому поиск по выбору выполняется по каждому запросу независимо от того, какой вид используется.

Я подумал, что, может быть, положить выбор = bodystyle_choices, без кронштейна будет работать, но я получаю:

'function' object is not iterable

Очевидно, что я могу использовать кэширование и поставить «импорт my_forms» только в функциях просмотра требуется, но это не измените главное: мои выборы должны быть ленивыми!

ответ

43

Вы можете использовать "ленивый" функцию :)

from django.utils.functional import lazy 

class CarSearchForm(forms.Form): 
    # lots of fields like this 
    bodystyle = forms.ChoiceField(choices=lazy(bodystyle_choices, tuple)()) 

очень хорошая функция Util!

+1

Определенно превосходное решение, это должен быть принятый ответ imo. –

+1

/Согласие - это самое чистое решение, которое я видел до сих пор, и это позволяет пропустить проблемы с проверками, что является важным отличием от ModelChoiceField. – Hassek

+7

Это не работает, по крайней мере, с Django 1.6, потому что 'ChoiceField._set_choices' делает' self._choices = self.widget.choices = list (value) ' – spookylukey

18

Попробуйте использовать ModelChoiceField вместо простого ChoiceField. Я думаю, вы сможете достичь того, чего хотите, немного изменив свои модели. Взгляните на номер docs.

Я хотел бы также добавить, что ModelChoiceFields являются lazy по умолчанию :)

0

Расширение на то, что сказал Baishampayan Гхош, это, вероятно, следует считать наиболее прямым подходом:

from django.forms import ModelChoiceField 

class BodystyleChoiceField(ModelChoiceField): 
    def label_from_instance(self, obj): 
     return '%s (%s cars)' % (obj.bodystyle_name, obj.car_set.count())) 

class CarSearchForm(forms.Form): 
    bodystyle = BodystyleChoiceField(queryset=Bodystyle.objects.all()) 

Docs здесь: https://docs.djangoproject.com/en/1.8/ref/forms/fields/#modelchoicefield

Это имеет то преимущество, что form.cleaned_data['bodystyle'] является Bodystyle экземпляром вместо строка.