Some Migration errors in Django 🤯 (emotional long post)

You ran makemigrations, then migrate and yet Django dares to throw an error? Incomparable betrayal! Let’s look through several cases.

Sidenote

For ages encountering migrations errors, I have been wipin the entire database and migrations files. Until one day an error occurred at a production server. There was no other option but to calm down and learn how to fix it.

🧸 Relation does not exist 1: not applied by you or Django

Run the command showmigrations and look at the output. If you see something like this:

firstapp
 [X] 0001_initial
 [X] 0002_auto_20190819_2019
 [X] 0003_auto_20190827_2311
 [ ] 0004_testunit

That means that the 0004 migrations was not applied, so just run migrate. If it stays misapplied or to avoid wasting time you can run this:

migrate firstapp 0004_testunit

If not, look further.

💔 Relation does not exist 2: You removed a migration’s file

Sidenote

The point of each migrations is to find the difference between the last version of the database structure and the current one. But Django does not look at the database itself, it compares your current models.py files with a virtual database made from migrations.py files. Then Django writes the changes down in new migrations files. And only with migrate you apply these changed to the database.

So if you remove something from migrations/ folder, the database will stay the same, but the Django’s idea of it won’t.

Case

So, you added a field type to a class Tag:

class Tag(models.Model)
   name = models.CharField(max_length=100)
   type = models.CharField(max_length=100)

You made a migrations, say, number 0002, it contains adding type field. Then you removed the migrations. After that, you made some changes, lived your best live, and decided to make migrations again.

Django will include creation of the type field to the migrations again. Therefore applying this migrations will give you an error:

ProgrammingError: column "tag_type" of relation "tag" already exists

How to Solve it 🧰

1. From migration file 0002_something.py remove the line about creating the type field.

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('firstapp', '0002_something'),
    ]

    operations = [
        ...
        # This .AddField below:
        migrations.AddField(
            model_name='tag',
            name='type',
            field=models.Charfield(max_length),
        ),
        ...
    ]

2. Migrate the 0002_something.py file:

migrate firstapp 0002_something

3. Make a new migration (it must only contain creating the type field):

makemigrations

4. Fake apply it like this:

 migrate firstapp 0003_something_two --fake

🔨 Relation does not exist 2: Renaming a field was not applied

This mysterious thing happened. I renamed type to type_name and I have a migrations that states it:

...    
    operations = [
        migrations.RenameField(
            model_name='tag',
            old_name='type',
            new_name='type_name',
        ),
    ]
...

And yet I get this error:

ProgrammingError at /test relation "firstapp_tag_type_name" does not exist

Possible culprit (myself and mass replace) a.k.a Sloppy Development installment

While changing names in the whole project automatically, I also unwillingly changed them in the migrations files. It is a great temptation to remove it all at once, but be careful. That may be the problem.

How to Solve it 🧰

Attempt #1: Order is wrong

The type field may have been altered before it was created because of the mass replace.

Try finding the whole life cycle of type field in your migrations – where it was added, where it was altered etc.

Attempt #2: Remove Migration file concerning the field

Remove every mention of the type field in migrations’ files (in operation). Then do whatever you want (rename it etc.) and make a migration again.

If the change is the only one in a migrations file, remove it all together.

You can remove the whole migration file, if it only contains type field manipulations. But be careful and alter dependencies for the following migration file (replace the deleted file’s name with the one before it).

Say, migrations’s files are 0002_something_before.py, 0003_something.py (removed) and 0004_brave_new.py.

So, after deleting 0003_something.py, in 0004_brave_new.py file:

dependencies = [
    ('firstapp', '0003_something'),
]

Replace 0003_something.py with0002_something_before:

dependencies = [
    ('firstapp', '0002_something_before'),
]

Otherwise you will get an error like this:

django.db.migrations.exceptions.NodeNotFoundError: Migration firstapp.0003_something_something dependencies reference nonexistent parent node 

Then, makemigrations and migrate.

Attempt #3: Remove every mention of the problematic field

If simply removing a migration and making another one doesn’t help…

Embrace yourself and remove every mention of type field. For my personal project, that inspired this post, it was quite time consuming.

However, as I see it now, you can’t just remove the field and make migrations of that, because type does not exist in the database. However, I can’t answer why.

You need to remove it from everywhere.

Then, makemigrations must show nothing, and the error won’t make am appearance.

🚫 Why you shouldn’t remove migrations

Summing up, Django does not care about database itself, except for when it returns errors. So Django’s idea of the database is made of migrations it have. That’s why when you run makemigrations, you get errors about migration files.

After applying new migrations, you will start getting all sorts of surprises: InvalidCursorName cursor does not exist or good old ProgrammingError: column does not exist and ProgrammingError: column of relation already exists.

Take my advice – don’t remove migrations because of migration errors, better learn how to work with them. Because in production you won’t be able to flush the database without a trouble (you kind of can, but you will need to insert missing data afterwards).

But if you did remove migrations…

Oh, been there.

I can say one thing – you will need to keep reversing changes to the database until you don’t get any more errors. And then make this changes again the same way I showed you here. And while in most cases Attempt #3 works, some day it may fail you.

One day I will emulate this and come back and update this post with a quick solution, but now I am triggered enough by just the mention of it.

Transforming one field to another

You can transform pretty much everything with an exception.

Adding a through table to M2M relation (or backwards)

Usually you want to add a through table to store additional data about the relation, not remove it. Either way, Django won’t allow this transition.

Say, Django can remove all the additional data, but constraints like unique_together can ruin your architecture. So you need to do it manually.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.