ChoiceField.choices 可调用对象如何知道 return 的选择?
How can a ChoiceField.choices callable know what choices to return?
在 Django 1.8 中,ChoiceField
的 choices
参数可以接受一个可调用对象:
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)
这还有一个好处,就是无需重新启动服务器即可进行更改。
在 Django 1.8 中,ChoiceField
的 choices
参数可以接受一个可调用对象:
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)
这还有一个好处,就是无需重新启动服务器即可进行更改。