Saving objects and their related objects at the same time in Django

11,686

Solution 1

transactions to the rescue !

from django.db import transaction

with transaction.atomic():
   post = Post.objects.create('My Title', 'My Body')
   post.tag_set = [Tag(post, 'test tag'), Tag(post, 'second test tag')]

As a side note: I think you really want a many to many relationship between Post and Tag...

Solution 2

override save...

class Post(models.Model):

    ...

    def save(self, *args, **kwargs):
        super(Post, self).save(*args, **kwargs)
        for tag in self.tag_set:
            tag.save()

This way you don't have to write the transaction thing over and over again. If you want to use transactions, just implement it in the save method instead of doing the loop.

Share:
11,686

Related videos on Youtube

AdamY
Author by

AdamY

Web developer

Updated on June 04, 2022

Comments

  • AdamY
    AdamY almost 2 years

    In Django, is there a way to create a object, create its related objects, then save them all at once?

    For example, in the code below:

    from django.db import models
    
    
    class Post(models.Model):
        title = models.CharField(max_length=255)
        body = models.CharField(max_length=255)
    
    
    class Tag(models.Model):
        post = models.ForeignKey(Post)
        title = models.CharField(max_length=255)
    
    post = Post(title='My Title', body='My Body')
    post.tag_set = [Tag(post=post, title='test tag'), Tag(post=post, title='second test tag')]
    post.save()
    

    I create a Post object. I then also want to create and associate my Tag objects. I want to avoid saving the Post then saving the Tags because if a post.save() succeeds, then a tag.save() fails, I'm left with a Post with no Tags.

    Is there a way in Django to save these all at once or at least enforce better data integrity?

    • Daniel Roseman
      Daniel Roseman over 7 years
      Isn't that what transactions are for?
  • raratiru
    raratiru over 6 years
    Nice thought but not correctly implemented. You need to call super twice. Here and here are two examples.
  • Ian Kirkpatrick
    Ian Kirkpatrick over 6 years
    I would disagree. They're doing super multiple times cause that's how their logic is set up. It doesn't matter how many times you call super. Technically you don't even have to call the super method at all. My logic here goes: do super post stuff, then do your stuff on top of super post stuff, then return the result. You're simply adding on to what happened in the super post. The examples you gave are actually doing something completely different than what is wanted in this question. It just happens to use a method that it is overriding. It's very much unrelated.
  • raratiru
    raratiru over 6 years
    The issue is that when I tried to implement this solution, post was a NoneType Object. This is probably because the save() method does not return something. I just found a good answer here.
  • Ian Kirkpatrick
    Ian Kirkpatrick over 6 years
    You will need to save the tags or use Tag.objects.create(...)
  • Ian Kirkpatrick
    Ian Kirkpatrick over 6 years
    You're right about the save not returning anything. I revised my answer. You still only need to call it once. It's just that self IS the Post object.