次のソリューションでは、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 を使用して単一のモデル フィールドに格納されたディクショナリから構築されたフォーム フィールドを個別に検証するためにそれを使用することに成功しました。