在def clean()上设置字段特定错误时发生KeyError

时间:2019-01-16 01:21:12

标签: django django-forms

我的表单中有一个多选字段。

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”。

1 个答案:

答案 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调用是一个很好的避免方法,当您开始遇到这样难以跟踪的错误时,就像您刚刚在此处发布的那样。