2009-02-20 7 views
19

tengo un my_forms.py Django así:opciones de descanso bajo la forma de Django

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

Cada elección es, por ejemplo, ("Saloon", "Saloon (15 autos)"). Entonces las elecciones son calculadas por esta función.

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

Mi problema es que las funciones de opciones se ejecutan cada vez que me limito a importar my_forms.py. Creo que esto se debe a la forma en que Django declara sus campos: en la clase pero no en un método de clase. Lo cual está bien, pero mi views.py importa my_forms.py para que las búsquedas de opciones se realicen en cada solicitud, sin importar qué vista se use.

pensé que tal vez poniendo opciones = bodystyle_choices sin soporte funcionaría, pero me sale:

'function' object is not iterable

Obviamente puede utilizar el almacenamiento en caché y poner los "my_forms importación" por si las funciones de vista necesarios, pero que no lo hace cambie el punto principal: ¡mis elecciones deben ser perezosas!

Respuesta

43

Puede utilizar la función de "perezosa" :)

from django.utils.functional import lazy 

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

muy agradable función util!

+1

Definitivamente la solución superior, esta debería ser la respuesta aceptada imo. –

+1

/agree es la solución más limpia que he visto hasta ahora y le permite saltear problemas con las validaciones, una diferencia importante con respecto a ModelChoiceField. – Hassek

+7

Esto no parece funcionar, al menos con Django 1.6, porque 'ChoiceField._set_choices' hace' self._choices = self.widget.choices = list (value) ' – spookylukey

18

Pruebe utilizar un ModelChoiceField en lugar de un simple ChoiceField. Creo que podrá lograr lo que quiere ajustando un poco sus modelos. Eche un vistazo a docs para más.

También me gustaría añadir que ModelChoiceFields son lazy por defecto :)

0

Ampliando lo que dijo Baishampayan Ghose, esto probablemente se debe considerar el enfoque más directo:

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

Esto tiene la ventaja de que form.cleaned_data['bodystyle'] es una instancia Bodystyle en lugar de una cuerda.

Cuestiones relacionadas