python - 为什么在 Django 中更改模型名称时必须声明 'atomic=False'?

标签 python django sqlite

好吧,我正在关注 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.

我用谷歌搜索并one Stackoverflow question说我应该添加 atomic=False 但他从未解释原因。

我还用谷歌搜索了official documentation对于“非原子迁移”,但仍然不明白为什么需要简单的模型名称更改。 (说实话,我很难理解这是什么。)

真的应该这样改型号吗?我做错了什么吗?

Non-atomic migrations

On databases that support DDL transactions (SQLite and PostgreSQL), migrations will run inside a transaction by default. For use cases such as performing data migrations on large tables, you may want to prevent a migration from running in a transaction by setting the atomic attribute to False:

最佳答案

TL;DR

您可以在 SQLite 中设置atomic=False使用 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 等(允许原子表重命名)。

关于python - 为什么在 Django 中更改模型名称时必须声明 'atomic=False'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51681660/

相关文章:

sqlite - 无法让 PHP session 保存处理程序 sqlite 工作

python - 是否可以扩展 QSlider 周围的可绘制区域

Django 修改网桥表

python - confluence-python 可以生成 avro 中的值和 string 中的键的数据吗?

django - 如何在Django的ModelForm中使用请求

python - 是否可以使用内置的 LogEntry 来跟踪每个用户的操作,而不仅仅是在管理页面中?

python - 简单的 CLI 待办事项管理器与 sqlite3 数据库存储问题

c# - 更新 System.Data.SQLite.dll 后 SQLite 无效的 URI

python - 如何断开与 elasticsearch-py 客户端/连接池的连接

python - 使用 Mechanize 登录