Django4 中文入门教程 Django4.0 迁移-迁移文件

2024-02-25 开发教程 Django4 中文入门教程 匿名 6

迁移以磁盘格式存储,这里称为“迁移文件”。这些文件实际上是普通的 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 ​检查哪些数据库的历史一致。