好的,所以我在official documentation上关注Django 2.0教程 当我意识到我将模型命名为“问题”而不是“问题”时。 (我是Django的新手)
我已经做过
$ python manage.py makemigrations polls
$ python manage.py migrate
所以我想我可以重复一遍以应用更改。
Django问我是否要重命名,所以我同意。
(venv) H:\PycharmProjects\django_tutorials\mysite>python manage.py makemigrations
Did you rename the polls.Questions model to Question? [y/N] y
Migrations for 'polls':
polls\migrations\0002_auto_20180804_0935.py
- Rename model Questions to Question
但是当我尝试迁移时,Django不会运行迁移并向我显示此错误。
(venv) H:\PycharmProjects\django_tutorials\mysite>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
Applying polls.0002_auto_20180804_0935...Traceback (most recent call last):
File "manage.py", line 15, in <module>
execute_from_command_line(sys.argv)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\core\management\__init__.py", line 381, in execute_from_command_line
utility.execute()
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\core\management\__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\core\management\base.py", line 316, in run_from_argv
self.execute(*args, **cmd_options)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\core\management\base.py", line 353, in execute
output = self.handle(*args, **options)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\core\management\base.py", line 83, in wrapped
res = handle_func(*args, **kwargs)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\core\management\commands\migrate.py", line 203, in handle
fake_initial=fake_initial,
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\db\migrations\executor.py", line 117, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\db\migrations\executor.py", line 147, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\db\migrations\executor.py", line 244, in apply_migration
state = migration.apply(state, schema_editor)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\db\migrations\migration.py", line 124, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\db\migrations\operations\models.py", line 330, in database_forwards
new_model._meta.db_table,
File "H:\PycharmProjects\django_tutorials\venv\lib\site-packages\django\db\backends\sqlite3\schema.py", line 84, in alter_db_table
) % old_db_table)
django.db.utils.NotSupportedError: Renaming the 'polls_questions' table while in a transaction is not supported on SQLite because it would break referential integrity. Try adding `atomic = False` to the Migration class.
我用Google搜索,one Stackoverflow question说我应该添加atomic=False
,但他从未解释原因。
我还在official documentation上搜索了“非原子迁移”,但仍然看不到为什么需要简单的模型名称更改。 (说实话,很难理解我的意思。)
真的应该这样来更改型号名称吗?我做错了什么吗?
非原子迁移
在支持DDL事务的数据库上 (SQLite和PostgreSQL),迁移将通过 默认。对于诸如在大型计算机上执行数据迁移的用例 表中,您可能要阻止迁移在 通过将atomic属性设置为False进行交易:
答案 0 :(得分:0)
TL; DR
您可以在SQLite上set atomic=False
或use PostgreSQL, MySQL
进行原子表重命名。
详细信息
也许您已经知道,此错误在django\db\backends\sqlite3\schema.py", line 84, in alter_db_table
处出现
如果您想知道为什么可以看到此代码。 (这将覆盖base/schema.py
)https://github.com/django/django/blob/master/django/db/backends/sqlite3/schema.py#L77
def alter_db_table(self, model, old_db_table, new_db_table, disable_constraints=True):
if disable_constraints and self._is_referenced_by_fk_constraint(old_db_table):
if self.connection.in_atomic_block:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # if checked atomic, raise NotSupportedError
raise NotSupportedError((
'Renaming the %r table while in a transaction is not '
'supported on SQLite because it would break referential '
'integrity. Try adding `atomic = False` to the Migration class.'
) % old_db_table)
self.connection.enable_constraint_checking()
super().alter_db_table(model, old_db_table, new_db_table)
self.connection.disable_constraint_checking()
else:
super().alter_db_table(model, old_db_table, new_db_table)
然后您可以比较默认的Postgresql或Mysql(它们不会覆盖base/schema.py
)https://github.com/django/django/blob/master/django/db/backends/base/schema.py#L399
def alter_db_table(self, model, old_db_table, new_db_table):
"""Rename the table a model points to."""
if (old_db_table == new_db_table or
(self.connection.features.ignores_table_name_case and
old_db_table.lower() == new_db_table.lower())):
return
self.execute(self.sql_rename_table % {
"old_table": self.quote_name(old_db_table),
"new_table": self.quote_name(new_db_table),
})
# Rename all references to the old table name.
for sql in self.deferred_sql:
if isinstance(sql, Statement):
sql.rename_table_references(old_db_table, new_db_table)
摘要
Django的Sqlite3不允许原子选项重命名表。
您可以使用Django的Postgresql,Mysql等(允许原子表重命名)。
答案 1 :(得分:0)
简短答案:
是的,这是更改型号名称的方法。您做对了,就像您提到的non-atomic migrations中所述。
详细答案:
SQLite是一个事务数据库,所有更改和查询都可以 原子的,一致的,隔离的和持久的(ACID)。
Atomic表示当您提交事务时,整个 交易是否适用。
默认情况下,SQLite在自动提交模式下运行。这意味着 每个命令,SQLite都会启动,处理和提交事务 自动。
现在假设您的数据库中有几个表,您决定重命名其中一个表。 SQLite自动启动事务,并在该事务中尝试重命名表。但是,例如,您的表被其他表引用,因此引发了异常(如您从@EunChong Lee先前提供的代码中可以看到的那样。)
if self.connection.in_atomic_block:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # if checked atomic, raise NotSupportedError
raise NotSupportedError((
'Renaming the %r table while in a transaction is not '
'supported on SQLite because it would break referential '
'integrity. Try adding `atomic = False` to the Migration class.'
) % old_db_table)
因此,当您在迁移文件中使用行atomic = False
时:
from django.db import migrations
class Migration(migrations.Migration):
atomic = False
您可以跳过此异常,然后继续重命名表,是的,对我来说看起来并不那么好,但是很好。
幕后发生的事情对我来说也不是很清楚,我想人们应该更多地研究django\db\backends\sqlite3\schema.py
中的代码,以更深入地了解如何用atomic=False
固定引用以及在什么情况下进行固定。在实施更改时,我们应该更加小心。