escolhas preguiçosos em forma de Django
-
05-09-2019 - |
Pergunta
Eu tenho um my_forms.py Django assim:
class CarSearchForm(forms.Form):
# lots of fields like this
bodystyle = forms.ChoiceField(choices=bodystyle_choices())
Cada escolha é por exemplo ( "Saloon", "Saloon (15 carros)"). Assim, as escolhas são computados por esta função.
def bodystyle_choices():
return [(bodystyle.bodystyle_name, '%s (%s cars)' %
(bodystyle.bodystyle_name, bodystyle.car_set.count()))
for bodystyle in Bodystyle.objects.all()]
O meu problema é as escolhas funções estão sendo executados cada vez que eu my_forms.py meramente importação. Eu acho que isso é devido à forma como Django declara seus campos: na classe, mas não em um método de classe. O que é bom, mas os meus importações views.py my_forms.py assim as pesquisas escolhas são feitas em cada solicitação, não importa qual modo de exibição é usado.
Eu pensei que as escolhas talvez colocando = bodystyle_choices sem suporte iria funcionar, mas eu recebo:
'function' object is not iterable
Obviamente, eu posso usar o cache e colocar os "my_forms importação" apenas nas funções de visualização necessários, mas isso não muda o ponto principal: as minhas escolhas precisam ser preguiçoso
Solução
Você pode usar a função de "preguiçoso":)
from django.utils.functional import lazy
class CarSearchForm(forms.Form):
# lots of fields like this
bodystyle = forms.ChoiceField(choices=lazy(bodystyle_choices, tuple)())
muito bom função util!
Outras dicas
Tente usar um ModelChoiceField em vez de um simples ChoiceField. Eu acho que você vai ser capaz de conseguir o que você quer por ajustes seus modelos um pouco. Dê uma olhada na docs para mais.
Eu também acrescentaria que ModelChoiceFields são lazy
por padrão:)
Expandindo o que Baishampayan Ghose disse, isso provavelmente deve ser considerada a abordagem mais direta:
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á aqui: https://docs.djangoproject.com /en/1.8/ref/forms/fields/#modelchoicefield
Isto tem a vantagem de que form.cleaned_data['bodystyle']
é um exemplo Bodystyle
em vez de uma string.
Agora você pode apenas usar (desde que eu acho que Django 1.8):
class CarSearchForm(forms.Form):
# lots of fields like this
bodystyle = forms.ChoiceField(choices=bodystyle_choices)
Observe o parêntese ausente. Se você precisar passar argumentos, eu só fazer uma versão especial da função com eles codificado apenas para esse formulário.