Ленивый выбор в форме Джанго - PullRequest
21 голосов
/ 20 февраля 2009

У меня есть 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 объявляет свои поля: в классе, но не в методе класса. Это нормально, но my views.py импортирует my_forms.py, поэтому поиск вариантов выполняется при каждом запросе, независимо от того, какое представление используется.

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

'function' object is not iterable

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

Ответы [ 4 ]

47 голосов
/ 10 мая 2009

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

from django.utils.functional import lazy

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

очень хорошая утилита!

18 голосов
/ 20 февраля 2009

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

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

1 голос
/ 08 апреля 2015

В продолжение того, что сказал Байшампаян Гхос, этот подход, вероятно, следует считать самым прямым:

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 вместо строки.

0 голосов
/ 27 марта 2019

Теперь вы можете просто использовать (так как я думаю, Django 1.8):

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

Обратите внимание на пропущенные скобки. Если вам нужно передать аргументы, я просто создаю специальную версию функции, которая жестко закодирована для этой формы.

...