I'm using CBV CreateView to display a couple of pages with formsets to the user.
When the model behind a given formset/CreateView is a common one (it will became clearer later), everything works fine using the following logic on the view:
class Create(CreateView):
...
def form_valid(self, formset):
instances = formset.save(commit=False)
for instance in instances:
instance.user = self.request.user
instance.save()
return super(Create, self).form_valid(formset)
However, on one of the models, I had to add extra actions to the model save() method. Namely, I need to create child objects when the parents are saved. Something like:
class Parent(models.Model):
...
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.child_set.create(...., *args, **kwargs)
In this particular case, the child object is being created twice and I believe that the formset.save(commit=False) is the culprit.
I tried replacing the child_set.create() for
child = Child(...parameters, parent=self)
child.save(*args, **kwargs)
But it yields the same result. How can I prevent that?
The .form_valid(…)
method [Django-doc] of a CreateView
[Django-doc], will call .save()
on the form
, and this will thus invoke a new round of saving all objects.
You can set the .user
of the instances, and then let the CreateView
save these instances. This thus means that you implement this as:
class Create(CreateView):
# …
def form_valid(self, formset):
instances = formset.save(commit=False)
for instance in instances:
instance.user = self.request.user
# no instance.save()
# ↓ this will save the instances
return super().form_valid(formset)
That being said, it might be better to work with a .get_or_create(…)
[Django-doc] over a .create(…)
[Django-doc], since now you will create a Child
object each time you save the Parent
object, which is likely not the intended effect.