Migrations in Django

Migration is a way to create or alter tables in the database. In Django, the common workflow of working with models is as follows:

  1. Create or change models in models.py file.
  2. Create migration file.
  3. Commit changes to the database using the migration file created in step 2.

Here are two reasons why migration is the preferred way of creating or altering tables instead of manually executing SQL queries.

  1. Writing SQL queries takes time and they are error-prone. On the other hand, migration is quite easy and doesn’t require to write any SQL.
  2. Using migrations you can revert back your entire databases to sometime back in the past with a single command. You could think of migrations as a version control for databases.

Let’s create some migrations.

Checking Models for Error

Django provides a check command which checks for errors in models.py file.

The "System check identified no issues (0 silenced)" indicates that no errors were found. Now we are ready to create our first migration. You should always use the check command to look for errors in your models before creating a migration file.

Creating Migrations

We use makemigrations command to create migrations. Open terminal and type the following command.

In the above command, we have specified the blog app, although this is optional. If not specified then Django would create migrations for all installed apps, only if there are any changes in the models.py file of the respective app.

Django will create migrations or migration file only when it detects changes in the models.py file. Try running the makemigrations command once again but this time without specifying the name of the app.

Because there are no new changes since the last time we executed makemigrations command, we get "No changes detected".

So what makemigrations command did?

The makemigrations command has created a migration file named 0001_initial.py in the migrations directory of the blog app. This migration file reflects the current state of our models. We will use this migration file to update our database. In other words, Django will use migration file to create SQL queries to update the current state of the database, so that it is in sync with models.py.

You can view the actual SQL queries that 0001_initial.py would generate to alter the current state of the database by using the sqlmigrate command. The sqlmigrate requires two arguments, name of the app and migration name. You don’t need to pass full name of the migration file, starting few characters is enough.

Note: Output is truncated to save space.

Lines starting with -- are comments, everything else is plain old SQL. It is important to note that sqlmigrate doesn’t commit these changes to the database, it just prints the raw SQL that Django would use to make changes to the database.

To commit these changes to the database Django provides another command called migrate.

But before we run migrate command. Let’s take a look at the current state of our database using Navicat.

database state before migrations applied

At this point, we have 11 tables in our database. Okay, now let’s run the migrate and see what happens.

If you don’t already have a database then migrate command will create an SQLite database named db.sqite3 in the project’s root directory i.e TGDB/django_project.

On the other hand, if you already have a database then Django will modify the existing database so that it is in sync with our models.

Let’s re-open our SQLite database and see how many tables are there now.

database state after migration applied

We now have 16 tables, the migrate command has created 5 new tables for us. Wait! why 5 ? we have created only 4 new models right? Why one extra?

Django has created an extra table (blog_post_tags) to manage a many-to-many relationship between post and tags. This is not specific to Django, in fact, this is how the database works.

All the tables which start with "blog_" belongs to the blog app. Here is the rundown of each table:

  • blog_author – to store authors.
  • blog_category – to store categories.
  • blog_tag – to store tags.
  • blog_post – to store blog posts.
  • blog_post_tags – to manage many-to-many relationship between post and tag. In database jargon, this table is known as Conjunction table.

Once More

Just to make sure you understand migrations completely. We will demonstrate it one more time. In this section, we are going to rename one of the fields of the Post model from pub_date to publication_date using migration and then we will revert the changes using migrations.

Open models.py inside the blog app and rename the field pub_date to publication_date as follows:


Step 1 – Check for errors in the model using the check command.

We don’t have any errors in models.py file. Let’s create our migration file now.

Step 2 – Create migration file using makemigrations command.

After executing makemigrations command Django will prompt you to verify the changes. Press Y or y to confirm. This will create a new migration file inside the migrations directory in the blog app.

Step 3 (optional) – View the SQL query that Django would use to update the database using the sqlmigrate command.

Well, that’s a lot of code for a single field rename. If you were not using migrations then you would have to write all this code by yourself. Thanks to migrations, you are in luck.

Step 4 – Commit the changes stored in the migration file to the database using the migrate command.

Rolling Back Migrations

Let’s say for some reason we don’t like the change we have made to the Post model. There are two ways to revert the changes we have made:

1st method

Change the name of field from publication_date to pub_date in models.py, create migration file and commit the changes:


Step 1 – Again check for errors using the check command.

Step 2 – Create migration file using the makemigrations command.

Step 3 (optional) – View SQL using sqlmigrate command.

Step 4 – Commit the changes to the database using the migrate command.

2nd method

Instead of modifying the models.py and creating new migration file using makemigrations command, we could just revert the migration using the migrate command. To do so, just pass the app_name followed by name of the migration file you want to migrate to. In this case, app_name is blog and the name of the migration file we want to migrate to starts with 0001. So, to revert the changes execute the following command.

I recommend you to run this command, even if you have already changed the column name to pub_date using the 1st method so that we are all on the same page.

Executing this command will not create any new migrations. At this point, you could again apply 0002 migration. By typing the following command.

However, We don’t want to ever come back to 0002 and 0003 migrations. So it is best to delete them from the migrations directory.

You are probably getting hang of this now. Hopefully, you should now have a better understanding of migrations in general and how they are used in Django. If you still have some confusion I suggest you re-read this chapter several times more.

Note: To checkout this version of the repository type git checkout 12a.

2 thoughts on “Migrations in Django

Leave a Comment

%d bloggers like this: