Ошибка при возврате автоматически сгенерированной миграции для переименования таблицы в Django

У меня возникают проблемы с возвратом миграции Django (1.8.7), которая содержит переименование таблицы. Несмотря на то, что он может переименовать его в Postgres, он затем пытается добавить ограничение, используя имя старой таблицы.

Здесь трассировка:

    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

Если вы посмотрите на SQL, который он генерирует,

[...]
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;

Вы можете видеть, что есть ссылка на team_membershiprole, хотя эта таблица больше не существует (она была переименована). Здесь код миграции:

# -*- 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'),
        ),
    ]

Я понимаю, что это может быть ошибка миграции Django, но есть ли способ обойти это?

Ответ 1

Вы можете переопределить Migration.unapply, чтобы он использовал другой набор операций.

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(..)

Я не тестировал это, но он должен дать вам представление. О, и вам может потребоваться изменить список обратных миграций, потому что Django будет ожидать, что он будет списком переходов вперед, чтобы пересечь их в обратном направлении.