如何在每个字段的MultiValueField / MultiWidget中呈现验证错误

时间:2012-09-03 10:16:39

标签: django

在一个表单中,我使用MultiValueField(MVF)和MultiWidget,它有几个字段。如果MVF的某个字段中存在验证错误,则会在MVF级别处理(显示),而不是在各个子字段处理,这可能导致:

* Ensure this value is greater than or equal to 1.
* Ensure this value is greater than or equal to -100.0.

Number of days: -1
...
...
Threshold: -200

第一个错误是指MVF的第一个字段,第二个错误是MVF的最后一个字段。

是否有可能将这些错误消息“置于”MVF内部所属的字段? (可能在MultiWidget的format_output方法中?)

1 个答案:

答案 0 :(得分:0)

以下解决方案不使用MultiValueField,而是使用:

  • 在表单__init__
  • 上动态替换原始字段
  • _post_clean
  • 上的表单验证期间重建原始字段的有效数据

以下是一些需要针对每种情况进行调整的测试代码:

class MyMultiField(CharField):

    def split(self, form):
        name = 'test'
        form.fields_backup[name] = form.fields[name]
        del form.fields[name]
        # here is where you define your individual fields:
        for i in range(3):
            form.fields[name + '_' + str(i)] = CharField()
            # you need to extract the initial data for these fields
            form.initial[name + '_' + str(i)] = somefunction(form.initial[name])
        form.fields['test_1'] = DecimalField() # because I only want numbers in the 2nd field

    def restore(self, form):
        # here is where you describe how to joins the individual fields:
        value = ''.join([unicode(v) for k, v in form.cleaned_data.items() if 'test_' in k])
        # extra step to validate the combined value against the original field:
        try:
            restored_data = form.cleaned_data.copy()
            restored_data["test"] = form.fields_backup["test"].clean(value)
            for k in form.cleaned_data:
                if k.startswith("test_"):
                    del restored_data[k]
            form.cleaned_data = restored_data
        except Exception, e:
            form._errors[NON_FIELD_ERRORS] = form.error_class(e)


class MyForm(Form):

    test = MyMultiField()

    def __init__(self, *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)
        self.fields_backup = {}
        self.fields['data'].split(self)

    def _post_clean(self):
        self.fields_backup['data'].restore(self)
        return super(MyForm, self)._post_clean()

在:

original form field

之后(验证一些输入):

multifield

我不确定是否可以使用此方法进一步解析此字段/表单代码。我对这段代码也不太满意,因为新的字段类需要从原始类继承。

尽管如此,基本的想法是存在的,我成功地使用它来单独验证使用PostgreSQL hstore从存储在单个模型字段中的字典构建的表单字段。