Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when reverting an auto-generated migration for renaming a table in Django

I'm having issues with reverting a Django (1.8.7) migration that contains the renaming of a table. Even though it seems to be able to rename it in Postgres, it then tries to add a constraint using the old table name.

Here's the traceback:

    cursor.execute(sql, params)
  File "/Users/myworkspace/projects/xxx/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/myworkspace/projects/xxx/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/myworkspace/projects/xxx/venv/lib/python3.5/site-packages/django/db/utils.py", line 97, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/myworkspace/projects/xxx/venv/lib/python3.5/site-packages/django/utils/six.py", line 658, in reraise
    raise value.with_traceback(tb)
  File "/Users/myworkspace/projects/xxx/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "team_membershiprole" does not exist

If you take a look at the SQL it generates,

[...]
ALTER TABLE "team_membershiprole" RENAME TO "team_leadershiprole";
[...]
ALTER TABLE "team_leadershipteammember" 
    ADD CONSTRAINT "team_l_role_id_xxx" 
    FOREIGN KEY ("role_id") REFERENCES "team_membershiprole" ("id")     
    DEFERRABLE INITIALLY DEFERRED;
[...]

COMMIT;

You can see that there's a reference to team_membershiprole, even though that table doesn't exist anymore (it was renamed). Here's the migration code:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
        ('core', '0023_xxx'),
        ('team', '0009_xxx2'),
    ]

    operations = [
        migrations.CreateModel(
            name='TeamMembership',
            fields=[
                ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
                ('team', models.ForeignKey(related_name='members', to='team.Team')),
                ('member', models.ForeignKey(to='core.Member')),
            ],
        ),
        migrations.RenameModel(
            old_name='LeadershipRole',
            new_name='MembershipRole',
        ),
        migrations.RemoveField(
            model_name='leadershipteammember',
            name='team',
        ),
        migrations.RemoveField(
            model_name='leadershipteammember',
            name='member',
        ),
        migrations.RemoveField(
            model_name='leadershipteammember',
            name='role',
        ),
        migrations.DeleteModel(
            name='LeadershipTeamMember',
        ),
        migrations.AddField(
            model_name='teammembership',
            name='role',
            field=models.ForeignKey(to='team.MembershipRole'),
        ),
    ]

I understand this is might be a Django migrations bug, but is there any way to work around it?

like image 666
Alexandre Cordeiro Avatar asked Dec 10 '15 14:12

Alexandre Cordeiro


People also ask

Can I rename a migration Django?

If it's a brand new migration, 2 and 3 won't apply, and it's perfectly fine to rename them.


1 Answers

You can override Migration.unapply so it uses a different set of operations.

class MyMigration(Migration):
    operations = [
        ... your operations ...
    ]
    reverse_operations = [
        ... your fixed reverse operations ...
    ]
    def unapply(self, project_state, schema_editor, collect_sql=False):
        self.operations = self.reverse_operations
        return super(MyMigration, self).unapply(..)

I have not tested this but it should give you an idea. Oh and you might need to reverse the list of reverse migrations because Django will be expecting it to be the list of forward migrations so traverse them in reverse.

like image 159
Ronald Avatar answered Oct 04 '22 20:10

Ronald