Django4.0 迁移-迁移文件
迁移以磁盘格式存储,这里称为“迁移文件”。这些文件实际上是普通的 Python 文件,具有约定的对象布局,以声明式风格编写。
基本的迁移文件如下所示:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [('migrations', '0001_initial')]
operations = [
migrations.DeleteModel('Tribble'),
migrations.AddField('Author', 'rating', models.IntegerField(default=0)),
]
Django 在加载迁移文件(作为 Python 模块)时寻找的是 django.db.migrations.Migration
的子类,称为 Migration
。然后,它将检查此对象的四个属性,大多数情况下仅使用其中两个:
-
dependencies
,所依赖的迁移列表。 -
operations
,定义了此次迁移操作的 Operation
类的列表。
operations
是关键;它们是一组声明性指令,它们告诉 Django 需要对哪些架构变更。Django 扫描它们并构建所有应用的所有架构变更的内存表示形式,然后使用它生成进行架构变更的 SQL。
该内存结构还用于确定模型与迁移当前状态之间的差异;Django 按顺序在内存中的模型集上运行所有的变更,得出你上次运行 makemigrations
时模型的状态。然后,它使用这些模型与你的 models.py
文件中的模型进行比较,以计算出你改变了什么。
你应该很少需要手动编辑迁移文件,但如果需要,完全可以手动编写。有些更复杂的操作是无法自动检测的,只能通过手写的迁移来实现,所以如果必须手写它们,也不要害怕。
自定义字段
你不能修改一个已经迁移的自定义字段中的位置参数的数量,否则会引发 TypeError
。旧的迁移会用旧的签名调用修改后的 __init__
方法。所以如果你需要一个新的参数,请创建一个关键字参数,并在构造函数中添加类似 assert 'argument_name' in kwargs
的内容。
模型管理器
你可以选择将管理器序列化为迁移,并在 RunPython
操作中使用它们。这是通过在 manager
类上定义一个 use_in_migrations
属性来实现的:
class MyManager(models.Manager):
use_in_migrations = True
class MyModel(models.Model):
objects = MyManager()
如果你使用 from_queryset()
函数动态生成管理器类,则需要从生成的类继承以使其可导入:
class MyManager(MyBaseManager.from_queryset(CustomQuerySet)):
use_in_migrations = True
class MyModel(models.Model):
objects = MyManager()
初始迁移
Migration.initial
应用的初始迁移是创建该应用首版表的迁移。 通常,一个应用有一个初始迁移,但是在某些情况下,复杂的模型依赖可能会导致两个或更多。
初始迁移在迁移类上标有 initial = True
类属性。如果未找到 initial
类属性,则如果迁移是应用程序中的第一个迁移(即,如果它不依赖于同一应用程序中的任何其他迁移)则将被视为初始。
当使用 migrate --fake-initial
选项时,将对这些初始迁移进行特殊处理。对于创建一个或多个表(CreateModel
操作)的初始迁移,Django 会检查所有这些表是否已经存在于数据库中,如果是,则对迁移进行假应用。 类似地,对于添加了一个或多个字段(AddField
操作)的初始迁移,Django 检查数据库中是否已存在所有相应的列,如果存在,则对迁移进行假应用。如果没有 --fake-initial
,初始迁移的处理方式和其他迁移没有区别。
历史一致性
历史一致性前面已经讨论过,当两个开发分支加入时,你可能需要手动线性化迁移。在编辑迁移依赖关系时,你可能会无意中创建一个不一致的历史状态,即一个迁移已经被应用,但它的一些依赖关系还没有应用。这强烈地表明依赖关系不正确,所以 Django 会拒绝运行迁移或进行新的迁移,直到它被修复。当使用多个数据库时,可以使用 database routers
的 allow_migrate()
方法来控制 makemigrations
检查哪些数据库的历史一致。
更多建议: