formset встроенных formsets в django 1.3+
У меня есть модель продукта и модель цены. Ценовая модель имеет FK для модели продукта. Может быть несколько цен (в зависимости от количества проданных единиц). Предыдущая версия django 1.2.5 http://yergler.net/blog/2009/09/27/nested-formsets-with-django/ могла бы решить эту проблему. Но, как подробно http://www.mail-archive.com/django-users@googlegroups.com/msg124195.html это больше не работает.
Конечный желаемый результат: следующая форма для редактирования и добавления данных.
Продукт Один - Цена Один, Количество - Цена Два, Количество Продукт Два - Цена Один, Количество Продукт Три - Цена Один, Количество - Цена Два, Количество - Цена Три, Количество
Воспроизведено для ясности:
В исходном коде Натана форма набора самого низкого уровня создается следующим образом:
TenantFormset(data=self.data,
instance=instance,
prefix='TENANTS_%s' % pk_value)
где instance - это экземпляр Building, "parent" или контейнер для арендаторов, а self - это экземпляр
class BaseBuildingFormset(BaseInlineFormSet)
который создается следующим образом:
BuildingFormset = inlineformset_factory(models.Block,
models.Building,
formset=BaseBuildingFormset,
extra=1)
Чтобы обойти это, я перестал передавать self.data, что привело к тому, что формы на самом нижнем уровне всегда имели is_bound = False, даже после того, как они были отрисованы и отправлены обратно в представление. Следовательно, проверка всегда заканчивается неудачей, и объекты, которые представляют формы, не могут быть обновлены. Я воспроизвел поведение, используя код из поста Натана в блоге, поэтому кажется, что этот подход к вложению наборов форм больше не действителен, или код нуждается в настройке для работы на 1.3.
До Django 1.2.5 код Натана работает нормально. Однако в 1.3, если self.data передается в TenantFormset, он оказывается пустым, и возникает ошибка ValidationError, поскольку информация ManagementForm не была предоставлена.
Это предполагаемое последствие #11418, AFAICT.
Есть ли у кого-нибудь еще идеи о том, как это можно сделать?
Ура,
(Извините за отсутствие подробных примеров кода - пост Натана намного яснее, чем мой код, поэтому я рекомендую вам взглянуть на это.)
Общее примечание: кажется, что существует много путаницы относительно того, как это сделать, что показано в ответах здесь http://www.reddit.com/r/django/comments/hwyto/is_there_a_way_to_do_nested_formsets_in_django/
3 ответа
Как говорит django docs, необходимо передать data = None, если форма не связана:
data = None
if self.data:
data = self.data
form.nested = [ModelXYFormset(data=data, instance = instance, prefix = 'opt%s' % pk_value)]
Вот обходной путь, который, кажется, работает в отношении получения подподформ для проверки.
В BaseBuildingFormset:
def is_valid(self):
result = super(BaseProtocolEventFormSet, self).is_valid()
for form in self.forms:
if hasattr(form, 'nested'):
for n in form.nested:
n.data = form.data
if form.is_bound:
n.is_bound = True
for nform in n:
nform.data = form.data
if form.is_bound:
nform.is_bound = True
# make sure each nested formset is valid as well
result = result and n.is_valid()
return result
Данные для каждой формы и набора форм должны быть одинаковыми (полные данные POST). Здесь мы вручную устанавливаем это для форм, которые не получают его. Мы также можем видеть, что в классе BaseForm is_bound просто проверяет, что форма имеет данные или файлы, поэтому, как только в форме есть данные, мы устанавливаем для нее значение true.
Я сейчас пытаюсь сделать то же самое. Я реализовал то же решение из кода Натана, но столкнулся с ValidationError
вопрос. В нашем Django 1.3 обновлено, как работают наборы форм, как показано здесь. Так что для моего кода,
TenantFormset(data=self.data, instance=instance, prefix='TENANTS_%s' % pk_value)
становится
TenantFormset(instance=instance, prefix='TENANTS_%s' % pk_value)
Но я все еще получаю чистую форму, хотя.