以下解决方案不使用 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()
前:
之后(验证一些输入):
我不确定是否可以使用这种方法进一步解耦此字段/表单代码。我对这段代码也不太满意,因为新的字段类需要从原来的类继承。
尽管如此,基本的想法是存在的,我成功地使用它来单独验证从存储在 PostgreSQL hstore 的单个模型字段中的字典构建的表单字段。