Django: save(commit=False) на наборе форм CBV вызывает действия save() настраиваемой модели
Я использую CBV CreateView для отображения пользователю пары страниц с наборами форм.
Когда модель, лежащая в основе данного набора форм/CreateView, является обычной (это станет ясно позже), все прекрасно работает при использовании следующей логики на представлении:
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)
Однако в одной из моделей мне пришлось добавить дополнительные действия в метод сохранения модели save(). А именно, мне нужно создавать дочерние объекты при сохранении родительских. Что-то вроде:
class Parent(models.Model):
...
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.child_set.create(...., *args, **kwargs)
В данном конкретном случае дочерний объект создается дважды, и я полагаю, что виной тому является formset.save(commit=False).
Я попробовал заменить child_set.create() на
child = Child(...parameters, parent=self)
child.save(*args, **kwargs)
Но это дает тот же результат. Как я могу предотвратить это?
Метод .form_valid(…)
[Django-doc] из CreateView
[Django-doc], вызовет .save()
на form
, и это вызовет новый раунд сохранения всех объектов.
Вы можете установить .user
экземпляры, а затем позволить CreateView
сохранить эти экземпляры. Таким образом, это означает, что вы реализуете это как:
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)
С учетом этого, возможно, лучше работать с .get_or_create(…)
[Django-doc], чем с .create(…)
[Django-doc], поскольку теперь вы будете создавать Child
объект при каждом сохранении Parent
объекта, что, вероятно, не является желаемым эффектом.