Ленивый выбор в форме Django
-
05-09-2019 - |
Вопрос
У меня есть Django my_forms.py вот так:
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 объявляет свои поля:в классе, но не в методе класса.Это нормально, но мой views.py импорт my_forms.py таким образом, поиск вариантов выполняется по каждому запросу независимо от того, какой вид используется.
Я подумал, что, возможно, размещение choices=bodystyle_choices без скобок сработало бы, но я получаю:
'function' object is not iterable
Очевидно, что я могу использовать кэширование и поместить "import my_forms" только в требуемые функции просмотра, но это не меняет сути:мой выбор должен быть ленивым!
Решение
Вы можете использовать "ленивую" функцию :)
from django.utils.functional import lazy
class CarSearchForm(forms.Form):
# lots of fields like this
bodystyle = forms.ChoiceField(choices=lazy(bodystyle_choices, tuple)())
очень приятная полезная функция!
Другие советы
Попробуйте использовать ModelChoiceField вместо простого ChoiceField.Я думаю, вы сможете достичь того, чего хотите, немного изменив свои модели.Взгляните на Документы для большего.
Я бы также добавил, что ModelChoiceFields - это lazy
по умолчанию :)
Развивая то, что сказал Байшампаян Гхосе, это, вероятно, следует считать наиболее прямым подходом:
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())
Документы находятся здесь: https://docs.djangoproject.com/en/1.8/ref/forms/fields/#modelchoicefield
Это имеет то преимущество, что form.cleaned_data['bodystyle']
является Bodystyle
экземпляр вместо строки.
Теперь вы можете просто использовать (так как я думаю, что Django 1.8):
class CarSearchForm(forms.Form):
# lots of fields like this
bodystyle = forms.ChoiceField(choices=bodystyle_choices)
Обратите внимание на отсутствующую круглую скобку.Если вам нужно передать аргументы, я просто создаю специальную версию функции с их жестким кодом только для этой формы.