我的表单中有一个多选字段。
paymentoption = forms.MultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
super(BasisOfPricingForm, self).__init__(*args, **kwargs)
self.fields['paymentoption'].choices = [(t.id, t.title) for t in PaymentOption.objects.all()]
def clean(self):
cleaned_data = super(BasisOfPricingForm, self).clean()
paymentoption = cleaned_data.get('paymentoption')
if paymethod1 == 3 and len(paymentoption) == 0:
self.add_error('paymentoption', 'You must select at lease one Offline Payment Option if users must pay in person or over the phone.')
当满足错误条件时,我在“付款方式”字段上收到“ KeyError”。
答案 0 :(得分:1)
我会给你一些提示:
首先,大多数时候您都没有(并且不想弄乱表单的初始值设定项)
与其在表单的paymentoption
中初始化__init__
选择的值,不如为此创建一个CustomMultipleChoiceFiled
。
例如:
class PaymentOptions(MultipleChoiceField):
def __init__(self, choices=None, **kwargs):
super(PaymentOptions, self).__init__(choices=choices, **kwargs)
if choices is None:
self.choices = # ...
然后,您可以使用它而不会弄乱表单的__init__
。
第二,如果不是绝对必要,请不要重新实现clean
,您可以添加一个名为clean_paymentoption
的方法并在那里执行所有必要的验证。
您可以在文档中阅读以下内容:
在表单子类上调用
clean_<fieldname>()
方法-其中<fieldname>
被表单字段属性的名称替换。此方法执行特定于该特定属性的任何清理,而与该字段的类型无关。此方法未传递任何参数。您将需要在self.cleaned_data中查询该字段的值,并记住这时它将是一个Python对象,而不是表单中提交的原始字符串(它将在cleaned_data中,因为常规字段clean()方法,上面的数据已经清除了一次)。例如,如果您想验证名为 serialnumber 的CharField的内容是唯一的,则 clean_serialnumber()将是正确的选择。您不需要特定的字段(仅是CharField),但是需要特定于表单字段的验证,并且可能需要清理/规范化数据。
此方法的返回值替换了cleaned_data中的现有值,因此它必须是cleaned_data中的字段值(即使此方法未更改)或新的cleaned值。
在您的情况下,可能是:
def clean_paymentoption(self):
paymentoption = self.cleaned_data.get('paymentoption', None)
if paymethod1 == 3 and len(paymentoption) == 0:
self.add_error('paymentoption', 'You must select at lease one Offline Payment Option if users must pay in person or over the phone.')
同样,您避免了另一个super
调用,并且super
调用是一个很好的避免方法,当您开始遇到这样难以跟踪的错误时,就像您刚刚在此处发布的那样。