Django formset validation - is_valid() == True, но возвращает пустую дикту clean_data для последней формы
У меня возникла проблема, когда я проверяю набор форм и когда я не предоставляю данные для (не обязательного) поля, он возвращает пустой dict. Чтобы понять, где я ошибаюсь, я создал сокращенную версию формы, с меньшим количеством полей, но точно такой же логикой init
. Сокращенная форма работает как ожидалось, когда поле присутствует и удаляется, но полная форма не работает. Поскольку кроме количества полей нет никакой разницы между формами и входными данными, я немного озадачен, почему.
Для ясности - поля формы создаются динамически на основе initial_data
или (POST) data
(из kwargs
) (с использованием field_mappings
диктанта).
class MyScaledDownForm(forms.Form):
field_mappings = {
"id": {
"field": forms.IntegerField(
help_text="",
widget=forms.HiddenInput(),
)
},
"defender": {"field": forms.CharField(help_text="", required=False)},
"sid_number": {
"field": forms.CharField(
required=False,
widget=forms.HiddenInput(),
help_text="",
)
},
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
initial_data = kwargs.get("initial")
validation_data = kwargs.get("data")
if initial_data:
for k, v in initial_data.items():
field_mapping = self.field_mappings.get(k)
if field_mapping:
self.fields[k] = field_mapping["field"]
self.fields[k].initial = v
elif validation_data:
for k, v in validation_data.items():
mk = k.split("-")[-1]
field_mapping = self.field_mappings.get(mk)
if field_mapping:
self.fields[mk] = field_mapping["field"]
else:
if args:
for k, v in args[0].items():
field_mapping = self.field_mappings.get(k)
if field_mapping:
self.fields[k] = field_mapping["field"]
elif kwargs:
for k, v in kwargs.items():
k = k.split("-")[-1]
field_mapping = self.field_mappings.get(k)
if field_mapping:
self.fields[k] = field_mapping["field"]
MyScaledDownFormSet = forms.formset_factory(
form=MyScaledDownForm,
extra=0,
)
а это полная форма с большим количеством полей, но точно такой же init
логикой:
Я ожидаю, что при одинаковых данных для проверки обе формы будут иметь одинаковые результаты, но это не так.
formset_input = {
"form-TOTAL_FORMS": "2",
"form-INITIAL_FORMS": "0",
"form-0-id": 7,
"form-0-defender": "defender_zero",
"form-1-id": 8,
"form-1-defender": "defender_one",
}
scaled_down_formset = MyScaledDownFormSet(request.POST)
my_formset = self.formset(request.POST)
print(f"my_formset - {scaled_down_formset.is_valid()}, {scaled_down_formset.cleaned_data}")
print(f"formset - {my_formset.is_valid()}, {my_formset.cleaned_data}")
Выход
scaled_down_formset - True, [{'id': 7, 'defender': 'defender_zero'}, {'id': 8, 'defender': 'defender_one'}]
my_formset - True, [{'id': 7, 'defender': 'defender_zero'}, {'id': 8, 'defender': 'defender_one'}]
Так что все в порядке, и работает как ожидалось. Теперь, когда я удаляю поля "защитника" из ввода, только одна форма работает так, как ожидалось:
formset_input = {
"form-TOTAL_FORMS": "2",
"form-INITIAL_FORMS": "0",
"form-new_comment": "Banana",
"form-0-id": 7,
# "form-0-defender": "defender_zero",
"form-1-id": 8,
# "form-1-defender": "defender_one",
}
scaled_down_formset = MyScaledDownFormSet(request.POST)
my_formset = self.formset(request.POST)
print(f"my_formset - {scaled_down_formset.is_valid()}, {scaled_down_formset.cleaned_data}")
print(f"formset - {my_formset.is_valid()}, {my_formset.cleaned_data}")
Выход
scaled_down_formset - True, [{'id': 7}, {'id': 8}] # cleaned data returns both dicts
my_formset - True, [{'id': 7}, {}] # cleaned data returns only the first dict