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 объекта, что, вероятно, не является желаемым эффектом.

Вернуться на верх