a blog about Django & Web Development

How to Create Rows in the Database with Django ORM

Django ORM (Object Relational Mapper) allows your application to modify your database with Python. This means you won’t have to write any SQL to manage your database. Django ORM will convert your code into SQL for you.

I am going to show you two ways to create objects in the database with Django ORM.

Prerequisites

You will need a Django application with a model.

If you’re new to Django, I have a post explaining what models are. I also have a beginners tutorial series that has a dedicated post about how to create a model for a To-Do list app.

What We’ll Cover

  1. Creating rows in the database
  2. How to only create rows if they don’t already exist
  3. Creating rows with Foreign Key fields
  4. Creating rows with ManyToMany fields
  5. Creating rows using form data (useful shortcut)
  6. Bulk creating rows

This post will not cover creating records using Class Based Views. This is a special case that will need its own post. In the meantime, I recommend this video by Very Academy, which provides a clear explanation.

Blog Example

The examples I’m about to give are all about creating posts for a simple blogging application.

This is a snippet from the Post model. The full source code for the models is on GitHub.

class Post(models.Model):

    STATUS_CHOICES = [
        ("draft", "Draft"),
        ("published", "Published"),
    ]

    title = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from="title", unique=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="draft")

    body = models.TextField()

    created_date = models.DateTimeField(auto_now_add=True)
    published_date = models.DateTimeField(blank=True, null=True)
    updated_date = models.DateTimeField(blank=True, null=True)

    tags = models.ManyToManyField(to=Tag, related_name="posts", blank=True)
    category = models.ForeignKey(
        to=Category,
        related_name="posts",
        default=get_category_id,
        on_delete=models.SET_DEFAULT,
        blank=False,
        null=False,
    )

    feature_image = models.ImageField(upload_to="uploads/", null=True, blank=True)

I have chosen this example because the Post model has several types of fields.

Some fields like the CharField and TextField are simplest to work with. The ForeignKey and ManyToMany fields are harder to understand, but we will cover them in this tutorial.

1. How to Create Rows in the Database

First, activate your virtual environment and start the shell.

python manage.py shell

I am using the shell so I can show you Django ORM in isolation. You can put your Django ORM code into a view or a script if you prefer.

Import the model

Before we can work with the model, we need to import it.

>>> from blog.models import Post

Create a Post

We can create a post using Post.objects.create( followed by values for each field.

>>> post = Post.objects.create(title="Test", body="abc")

>>> post
<Post: Test>

Django returns a Post object that represents our new record in the database. It binds the database ID of the row to the object.

>>> post.id
22

Some fields were assigned without explicitly defining them. For this example, the slug and created date were assigned automatically.

>>> post.slug
'test'
>>> post.created_date
datetime.datetime(2022, 12, 31, 21, 49, 26, 73097)
>>> post.category
<Category: Uncategorised>

Other fields are left blank as we did not define them. This includes tags and image.

>>> post.tags.all()
<QuerySet []>
>>> post.feature_image
<ImageFieldFile: None>

What is objects?

Objects refers to the Model Manager (docs) for the model. A model manager is simply a class that contains methods for communicating with the database. The create function is one of these methods.

The default model manager contains methods for creating, updating and deleting records from the database. It is possible to create custom managers to add additional functionality.

Post vs Post.objects.create

There are two ways to create records in the database.

The first is Post.objects.create shown above.

The other way is to create an instance of the Post class and use the save method to commit it to the database.

This is how to create the post instance.

>>> post = Post(title="My Post", body="abc")

>>> post
<Post: My Post>

Creating an instance of the Post model does not involve any activity with the database. It has no ID because it doesn’t exist in the database.

>>> type(post.id)
<class 'NoneType'>

However, you can call the save method to save it to the database.

>>> post.save()

>>> post.id
29

2. How to only create rows that don’t already exist

You can use get_or_create to ensure rows are only created if they don’t already exist in the database.

If a matching row is found, then Django returns a row as an instance of the model. If a match does not exist, then Django will create a new row and return it as an object.

get_or_create also returns a boolean. Its value is True if the record was just created, and False if it was in the database already.

>>> post, created = Post.objects.get_or_create(title="Test 2", body="abc")

>>> post
<Post: Test 2>

>>> created
True

>>> post.id
25

If we try to create the same post again, Django returns the existing post.

>>> post, created = Post.objects.get_or_create(title="Test 2", body="abc")

>>> post
<Post: Test 2>

>>> created
False

>>> post.id
25

3. How to Create Posts with Foreign Keys

Say we want to create a post with a category. In our example, we have a separate table for categories.

First, lets create a category.

>>> my_category = Category.objects.create(name="My Category")

>>> my_category
<Category: My Category>

When creating a post with a Foreign Key, we can supply the related object.

>>> post_3 = Post.objects.create(title="Post 3", body="abc", category=my_category)

>>> post_3.category
<Category: My Category>

We can also just provide the ID. This is useful when we have the ID of the related object but want to create a post without querying for the category first.

>>> post_4 = Post.objects.create(title="Post 4", body="abc", category_id=category_id)

>>> post_4.category
<Category: My Category>

Note, you have to specify category_id rather than category here.

I have a separate post explaining foreign keys in more detail, which also uses blog categories as an example.

4. How to Create Rows with a ManyToManyField

ManyToMany fields are a special case because they are defined after the row has been created (Django docs).

Let’s add some tags to a post.

First we’ll create some tags.

>>> from blog.models import Tag

>>> tag_1 = Tag.objects.create(name="Tag 1")
>>> tag_2 = Tag.objects.create(name="Tag 2")
>>> tag_3 = Tag.objects.create(name="Tag 3")

Then, create a post.

>>> post_5 = Post.objects.create(title="Post 5", body="abc")

Right now, it has no tags.

>>> post_5.tags.all()
<QuerySet []>

We can add a tag using .add

>>> post_5.tags.add(tag_1)

We can use post.tags.all() to query for tags assigned to the post.

>>> post_5.tags.all()
<QuerySet [<Tag: Tag 1>]>

We can also add multiple tags at once.

>>> post_5.tags.add(tag_2, tag_3)

>>> post_5.tags.all()
<QuerySet [<Tag: Tag 1>, <Tag: Tag 2>, <Tag: Tag 3>]>

I have a worked example of adding tags to a blog, which explains this in more detail.

5. Creating Rows Using Form Data

Neither my Basic Blog app (GitHub) and To-Do List app (GitHub) use Model.objects.create directly.

They use form.save() instead.

If you are using a model form to collect data from the user, you can use the save method of the form to create the post.

This is a snippet from views.py.

def add_post(request: HttpRequest) -> HttpResponse:

    if request.method == "POST":
        form = PostForm(data=request.POST, files=request.FILES)

        if form.is_valid():
            # form.save() creates a post from the form
            post: Post = form.save(commit=False)

            if post.feature_image:
                img: Image = utils.resize_image(
                    post.feature_image, constants.ImageWidth.LARGE
                )
                img.save(post.feature_image.path)

            post.save()

            return redirect("post_detail", slug=post.slug)

    else:
        form = PostForm()

    context = {"form": form, "edit_mode": False}

    return render(request, "post_form.html", context)

If you don’t specify commit=False, then Django will save the post to the database and return the post object.

If you specify commit=True, then Django will return an instance of the Post model without committing it to the database. This is useful when we want to add data that didn’t come in through the form before saving it to the database. In the code snippet above, we resized the image.

You can call save on model instances to save them to the database.

post.save()

6. Bulk Creating Rows

You may need to create lots of rows in one go.

For example, you may have a script that ingests data from a spreadsheet or an API.

Calling Post.objects.create( makes one call to the database.

If you are creating lots of posts, you can use bulk_create (Django docs) to improve performance by reducing the number of calls to the database.

Lets start with a list of titles and bodies for five posts.

>>> ingest = [("Title A", "a"), ("Title B", "b"), ("Title C", "c"), ("Title D", "d"), ("Title E", "e")]

Using a list comprehension, I can create a list of Post instances.

>>> post_instances = [Post(title=x[0], body=x[1]) for x in ingest]

>>> post_instances
[<Post: Title A>, <Post: Title B>, <Post: Title C>, <Post: Title D>, <Post: Title E>]

These are only instances of the Post model. Because we didn’t use Post.objects.create, nothing has been created in the database yet.

Using a bulk create, we can save all five post instances to the database in one go.

>>> posts = Post.objects.bulk_create(post_instances)

>>> posts
[<Post: Title A>, <Post: Title B>, <Post: Title C>, <Post: Title D>, <Post: Title E>]

Conclusion

We have covered how to use Django ORM to create records in a database.

We covered two useful Django ORM features: get_or_create which only creates records if a matching record doesn’t already exist and bulk_create, which offers improved performance if you need to create lots of rows at once.

When working with Django’s model forms, you can use form.save as a shortcut, and create rows from data submitted by the user.

Next Steps

By learning how to create data in the database, you have mastered the C in CRUD (Create, Read, Update, Delete).

The next step is to master reading from the database. For this, I have a beginner-friendly post on how to create database queries with filters.

Related Posts