I have a form in which I creates a new "parent" object, exactly one child object of type A and n child objects of type B (n can also be 0). I do this with a form and and two inlineformsets.
I have set in settings 'ATOMIC_REQUESTS': True
.
I'm using a function based view. The code for saving the data is like this:
if form.is_valid():
parent = form.save();
formsetA = AFormset(request.POST, instance=parent)
formsetB = BFormset(request.POST, instance=parente)
if formsetA.is_valid():
# save first form in inline formset (there always only is one)
# and then assign meta data
a = formset[0].save()
if formsetB.is_valid():
for b in formsetB:
if b.is_valid():
b.save()
Check if parent is valid, save it and set it as instance of the inline formsets. Then check the inline formsets. If a form is not valid I redirect back to the form. No exception.
Issue is that if a inlineformset is invalid, it returns to the form but the parent was already saved and transaction is not rolled back. If I roll back the transaction manually just before redirecting back to the form I get an exception:
An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
I assume I can't manually rollback inside atomic block?
My main question is how I should handle this situation correctly, eg. saving parent and child at once?
What solved the immediated issue is to not commit on parent form save and then first check formsets for validity before committing the parent:
if form.is_valid():
parent = form.save(commit=False);
formsetA = AFormset(request.POST, instance=parent)
formsetB = BFormset(request.POST, instance=parente)
if formsetA.is_valid() and formsetB.is_valid():
#formsets are valid, parent can be saved
# this assumes if formset is valid, all contained forms are too
parent.save()
a = formset[0].save()
for b in formsetB:
b.save()