2009-02-20 12 views
19

Mam my_forms.py Django tak:Lazy wybory w postaci Django

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

Każdy wybór jest np ("Saloon", "Saloon (15 samochodów)"). Więc wybory są obliczane przez tę funkcję.

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

Mój problem polega na tym, że funkcje wyboru są wykonywane za każdym razem, gdy tylko importuję my_forms.py. Myślę, że wynika to ze sposobu, w jaki Django deklaruje swoje pola: w klasie, ale nie w metodzie klasowej. Co jest w porządku, ale mój views.py importuje moje_forms.py, więc wyszukiwania wyborów są wykonywane dla każdego żądania bez względu na to, który widok jest używany.

Myślałem, że może wprowadzenie wyborów = bodystyle_choices bez wspornika będzie działać, ale mam:

'function' object is not iterable

Oczywiście można używać buforowania i umieścić „my_forms przywóz” tylko w funkcji widoku wymagane, ale to nie zmień główny punkt: moje wybory muszą być leniwy!

Odpowiedz

43

Można użyć funkcji "leniwe" :)

from django.utils.functional import lazy 

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

bardzo miły funkcji util!

+1

Zdecydowanie najlepsze rozwiązanie, to powinna być akceptowana odpowiedź imo. –

+1

/agree to najczystsze rozwiązanie, jakie dotychczas widziałem, dzięki czemu można pominąć problemy z walidacjami, co stanowi istotną różnicę w stosunku do ModelChoiceField. – Hassek

+7

To nie działa, przynajmniej z Django 1.6, ponieważ 'ChoiceField._set_choices' robi' self._choices = self.widget.choices = list (value) ' – spookylukey

18

Spróbuj użyć ModelChoiceField zamiast zwykłego ChoiceField. Myślę, że będziesz w stanie osiągnąć to, co chcesz, nieco ulepszając swoje modele. Spójrz na numer docs, aby uzyskać więcej informacji.

Chciałbym również dodać, że ModelChoiceFields są lazy domyślnie :)

0

Rozszerzając co Baishampayan Ghose powiedział, to prawdopodobnie powinien być uważany za najbardziej bezpośredni dojazd:

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 tutaj: https://docs.djangoproject.com/en/1.8/ref/forms/fields/#modelchoicefield

Ma to tę zaletę, że form.cleaned_data['bodystyle'] jest instancją Bodystyle zamiast strunowy.