如何使 Django 表单选择延迟计算?

问题描述 投票:0回答:4

my_forms.py

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

每个选择都是,例如,

("Saloon", "Saloon (15 cars)")
。这些选择是通过这个函数计算的:

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
放在所需的视图函数中,但这不会改变要点:我的选择需要偷懒!

python django forms lazy-evaluation
4个回答
51
投票

你可以使用“懒惰”功能:)

from django.utils.functional import lazy

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

非常好的实用函数!


18
投票

尝试使用 ModelChoiceField 而不是简单的 ChoiceField。我认为通过稍微调整你的模型你将能够实现你想要的。请查看 docs 了解更多信息。

我还要补充一点,ModelChoiceFields 默认情况下是

lazy
:)


2
投票

你现在可以使用(因为我认为 Django 1.8):

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

注意缺少的括号。如果您需要传递参数,我只需制作一个特殊版本的函数,并针对该形式对它们进行硬编码。


1
投票

扩展 Baishampayan Ghose 的说法,这可能应该被认为是最直接的方法:

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
实例而不是字符串。

© www.soinside.com 2019 - 2024. All rights reserved.