还原自动生成的迁移以在 Django 中重命名 table 时出错
Error when reverting an auto-generated migration for renaming a table in Django
我在 还原 包含重命名 table 的 Django (1.8.7) 迁移时遇到问题。即使它似乎能够在 Postgres 中重命名它,它也会尝试使用 old table 名称添加约束。
这是回溯:
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
的引用,尽管 table 已不存在(已重命名)。这是迁移代码:
# -*- 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 迁移错误,但有什么办法可以解决这个问题吗?
您可以重写 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 会期望它是正向迁移列表,所以反向遍历它们。
我在 还原 包含重命名 table 的 Django (1.8.7) 迁移时遇到问题。即使它似乎能够在 Postgres 中重命名它,它也会尝试使用 old table 名称添加约束。
这是回溯:
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
的引用,尽管 table 已不存在(已重命名)。这是迁移代码:
# -*- 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 迁移错误,但有什么办法可以解决这个问题吗?
您可以重写 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 会期望它是正向迁移列表,所以反向遍历它们。