ChoiceField.choices 可调用对象如何知道 return 的选择?

How can a ChoiceField.choices callable know what choices to return?

在 Django 1.8 中,ChoiceFieldchoices 参数可以接受一个可调用对象:

def get_choices():
    return [(1, "one"), (2, "two")]

class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=get_choices)

在上面的例子中,get_choices()总是returns相同的选择。但是,能够将可调用对象分配给 choices 没有多大意义,除非该可调用对象在每次调用时都知道诸如对象 ID 之类的信息。这种东西怎么传给它?

你不能在表单声明中这样做,因为the CallableChoiceIterator calls the function without arguments that he gets from here。 我想在 __init__ Form 方法中执行操作比创建自己的 ChoiceField 更容易。这是我的建议:

class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=())

    def __init__(self, *args, **kwargs):
        # Let's pass the object id as a form kwarg
        self.object_id = kwargs.pop('object_id') 

        # django metaclass magic to construct fields
        super().__init__(*args, **kwargs)

        # Now you can get your choices based on that object id            
        self.fields['my_choice_field'].choices = your_get_choices_function(self.object_id)

假设您有一些基于 Class 的视图,看起来有这样的方法:

class MyFormView(FormView):
   # ...

   def get_form_kwargs(self):
       kwargs = super().get_form_kwargs()
       kwargs['object_id'] = 'YOUR_OBJECT_ID_HERE'
       return kwargs

   # ...

P.S :super() 函数调用假设您使用的是 python 3

之所以可以设置这样的可调用对象,是为了避免在模型准备好之前就使用它们的情况。

forms.py

class Foo(ModelForm):
    choice_field = ChoiceField(choices=[
        user.username.lower() for user in User.objects.all()
    ])

在模型准备好之前导入了 forms.py,(这可能是因为 views.py 通常喜欢导入它,而 urls.py 通常喜欢导入 ,并且 urls.py 由启动机器导入),它会引发异常,因为在导入所有应用程序之前尝试执行 ORM 操作。

正确的方法是像这样使用可调用对象:

def lower_case_usernames():
    return [user.username.lower() for user in User.objects.all()]


class Foo(ModelForm):
    choice_field = ChoiceField(choices=lower_case_usernames)

这还有一个好处,就是无需重新启动服务器即可进行更改。