formset of inline formsets in django 1.3+
I have a product model, and a price model. The price model has a FK to the product model. There may be multiple prices (depending on the quantity of units sold). Previous to django 1.2.5 http://yergler.net/blog/2009/09/27/nested-formsets-with-django/ would sove the problem. But as detailed http://www.mail-archive.com/django-users@googlegroups.com/msg124195.html this no longer works.
End desired result: the following form to edit and add data.
Product One - Price One, Quantity - Price Two, Quantity Product Two - Price One, Quantity Product Three - Price One, Quantity - Price Two, Quantity - Price Three, Quantity
Reproduced for clarity:
In Nathan's original code, the lowest level formset is created like this:
TenantFormset(data=self.data,
instance=instance,
prefix='TENANTS_%s' % pk_value)
where instance is an instance of Building, the "parent" or container for tenants and self is an instance of
class BaseBuildingFormset(BaseInlineFormSet)
which is instantiated like this:
BuildingFormset = inlineformset_factory(models.Block,
models.Building,
formset=BaseBuildingFormset,
extra=1)
To get around this I stopped passing in self.data, which led to forms in the lowest layer always have is_bound = False, even after being rendered and POSTed back to the view. Consequently validation always fails and the objects that the forms represent cannot be updated. I've reproduced the behaviour using the code from Nathan's blog post, so it seems that this approach to nesting formsets is no longer valid, or the code needs a tweak to work at 1.3.
Up to Django 1.2.5, Nathan's code works fine. However at 1.3, if self.data is passed to TenantFormset, it turns out to be empty and a ValidationError is raised because the ManagementForm information has not been supplied.
This is the intended consequence of #11418, AFAICT.Does anyone have any other ideas on how this might be made to work?
Cheers,
(Sorry about the absence of detailed co开发者_如何学Gode examples - Nathan's post is much clearer than my code, so I'd recommend you look at that.)
General Note: there seems much confusion about just how to do this, shown by responses here http://www.reddit.com/r/django/comments/hwyto/is_there_a_way_to_do_nested_formsets_in_django/
As django docs says, it is necessary to pass data = None if the form is not bound:
data = None
if self.data:
data = self.data
form.nested = [ModelXYFormset(data=data, instance = instance, prefix = 'opt%s' % pk_value)]
I'm currently attempting the same thing. I had implemented the same solution from Nathan's code, but ran into the ValidationError
issue. Turns our Django 1.3 updated how the formsets work, as shown here. So for my code,
TenantFormset(data=self.data, instance=instance, prefix='TENANTS_%s' % pk_value)
becomes
TenantFormset(instance=instance, prefix='TENANTS_%s' % pk_value)
But I'm still getting a blank form though.
Here is a work-around that seems to work with regard to getting the sub-sub forms to validate.
In 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
The data for each form and formset should be the same (the full POST data). Here we manually set this for the forms which aren't getting it. We can also see that in the BaseForm class, is_bound simply verifies that the form has data or files, so once the form has data we set that to true.
精彩评论