迁移操作

迁移文件由一个或多个Operation组成,这些对象声明性地记录迁移应对数据库执行的操作。

Django还使用这些Operation对象来计算您的模型在历史上的看法,并计算自上次迁移以来对模型所做的更改,以便自动编写迁移;这就是为什么它们是声明性的,因为这意味着Django可以轻松地将它们全部加载到内存中,并通过它们遍历它们,而不需要触摸数据库来确定您的项目应该是什么样子。

还有更专门的Operation对象,用于像data migrations和高级手动数据库操作。 如果要封装常用的自定义更改,也可以编写自己的Operation类。

If you need an empty migration file to write your own Operation objects into, just use python manage.py makemigrations --empty yourappname, but be aware that manually adding schema-altering operations can confuse the migration autodetector and make resulting runs of makemigrations output incorrect code.

所有的核心Django操作都可以从django.db.migrations.operations模块获得。

有关介绍材料,请参阅migrations topic guide

模式操作

CreateModel

class CreateModel(name, fields, options=None, bases=None, managers=None)[source]

在项目历史中创建一个新模型,并在数据库中创建一个相应的表来匹配它。

name是model的名称,如写在models.py文件中。

fields(field_name, field_instance)的2元组的列表。 字段实例应该是一个未绑定字段(所以只是models.CharField(...),而不是从另一个模型中获取的字段)。

options是来自模型的Meta类的值的可选字典。

bases是此模型继承的其他类的可选列表;它可以包含类对象以及格式为"appname.ModelName"的字符串,如果你想依赖另一个模型(所以你从历史版本继承)。 如果没有提供,它默认只继承标准的models.Model

managers获取(manager_name, manager_instance)的2元组列表。 列表中的第一个管理器将成为迁移期间此模型的默认管理器。

DeleteModel

class DeleteModel(name)[source]

从数据库中删除项目历史中的模型及其表。

RenameModel

class RenameModel(old_name, new_name)[source]

将模型从旧名称重命名为新名称。

如果您一次更改模型的名称和相当多的字段,则可能需要手动添加此项;对于自动检测器,这将像您删除具有旧名称的模型,并添加一个具有不同名称的模型,并且其创建的迁移将丢失旧表中的任何数据。

AlterModelTable

class AlterModelTable(name, table)[source]

更改模型的表名(Meta子类上的db_table选项)。

AlterUniqueTogether

class AlterUniqueTogether(name, unique_together)[source]

更改模型的唯一约束集(Meta子类上的unique_together选项)。

AlterIndexTogether

class AlterIndexTogether(name, index_together)[source]

更改模型的自定义索引集(Meta子类上的index_together选项)。

AlterOrderWithRespectTo

class AlterOrderWithRespectTo(name, order_with_respect_to)[source]

_order子类上为order_with_respect_to选项创建或删除所需的Meta列。

AlterModelOptions

class AlterModelOptions(name, options)[source]

存储对Metapermissions的杂项模型选项(模型verbose_name 不会影响数据库,但会对RunPython实例保留这些更改以使用。 options应是将选项名称映射到值的字典。

AlterModelManagers

class AlterModelManagers(name, managers)[source]

更改迁移期间可用的管理器。

AddField

class AddField(model_name, name, field, preserve_default=True)[source]

向模型中添加字段。 model_name是模型的名称,name是字段的名称,field是一个未绑定的Field实例(您将放在字段声明中的内容)在models.py中,例如models.IntegerField(null=True)

preserve_default参数表示该字段的默认值是否是永久性的,并且应该被烘焙到项目状态(True),或者如果它是临时的并且仅适用于此迁移(False) - 通常是因为迁移将一个不可为空的字段添加到表中,并且需要一个默认值才能放入现有的行。 它不影响直接在数据库中设置默认值的行为 - Django从不设置数据库默认值,并始终将它们应用于Django ORM代码。

RemoveField

class RemoveField(model_name, name)[source]

从模型中删除字段。

请记住,当反转时,这实际上是向模型添加一个字段。 该操作是可逆的(除了任何数据丢失,当然是不可逆的),如果该字段为空,或者它具有可用于填充重新创建的列的默认值。 如果该字段不可为空,并且没有默认值,则该操作是不可逆的。

AlterField

class AlterField(model_name, name, field, preserve_default=True)[source]

更改字段的定义,包括对其类型,nulluniquedb_column和其他字段属性的更改。

preserve_default参数表示该字段的默认值是否是永久性的,并且应该被烘焙到项目状态(True),或者如果它是临时的并且仅适用于此迁移(False) - 通常是因为迁移将可空字段更改为不可空的字段,并且需要将默认值放入现有行。 它不影响直接在数据库中设置默认值的行为 - Django从不设置数据库默认值,并始终将它们应用于Django ORM代码。

请注意,并非所有数据库都进行所有更改 - 例如,您不能将models.TextField()等文本类型字段更改为数字类型字段(如models.IntegerField()在大多数数据库。

RenameField

class RenameField(model_name, old_name, new_name)[source]

更改字段名称(除非设置db_column,否则其列名称)。

AddIndex

class AddIndex(model_name, index)[source]
Django中的新功能1.11。

在具有model_name的模型的数据库表中创建一个索引。 indexIndex类的一个实例。

RemoveIndex

class RemoveIndex(model_name, name)[source]
Django中的新功能1.11。

model_name从模型中删除名为name索引。

特殊的操作

RunSQL

class RunSQL(sql, reverse_sql=None, state_operations=None, hints=None, elidable=False)[source]

允许在数据库上运行任意SQL - 对于Django不能直接支持的数据库后端的更高级功能(如部分索引)非常有用。

sqlreverse_sql(如果提供)应为在数据库上运行的SQL字符串。 在大多数数据库后端(除PostgreSQL之外),Django将在执行它们之前将SQL拆分为单独的语句。 这需要安装sqlparse Python库。

您还可以传递字符串或2元组的列表。 后者用于以与cursor.execute()相同的方式传递查询和参数。 这三个操作是等效的:

migrations.RunSQL("INSERT INTO musician (name) VALUES ('Reinhardt');")
migrations.RunSQL([("INSERT INTO musician (name) VALUES ('Reinhardt');", None)])
migrations.RunSQL([("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])])

如果要在查询中包括文字百分号,则必须将它们加倍(如果您正在传递参数)。

当迁移未应用时,执行reverse_sql查询,因此您可以反转转发查询中所做的更改:

migrations.RunSQL(
    [("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
    [("DELETE FROM musician where name=%s;", ['Reinhardt'])],
)

state_operations参数是这样的,所以您可以在项目状态方面提供与SQL相当的操作;例如,如果您手动创建列,则应在此处传入包含AddField操作的列表,以便自动检测器仍然具有模型的最新状态(否则,当您接下来运行makemigrations,它不会看到任何添加该字段的操作,因此将尝试再次运行它)。 像这样:

migrations.RunSQL(
    "ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
    state_operations=[
        migrations.AddField(
            'musician',
            'name',
            models.CharField(max_length=255),
        ),
    ],
)

可选的hints参数将作为**hints传递到数据库路由器的allow_migrate()方法,以帮助他们进行路由决策。 有关数据库提示的更多详细信息,请参阅Hints

可选的elidable参数用于确定squashing migrations时是否删除(删除)操作。

RunSQL。空操作 T0> ¶ T1>

当希望操作不在给定方向执行任何操作时,将RunSQL.noop属性传递到sqlreverse_sql 这在使操作可逆时尤其有用。

Django中的新功能1.10:

添加了elidable参数。

RunPython

class RunPython(code, reverse_code=None, atomic=None, hints=None, elidable=False)[source]

在历史上下文中运行自定义Python代码。 code(和reverse_code如果提供)应该是可接受两个参数的可调用对象;第一个是django.apps.registry.Apps的实例,其中包含与项目历史记录中的操作位置相匹配的历史模型,第二个是SchemaEditor的实例。

在取消应用迁移时调用reverse_code参数。 这个可调用应撤消在code中调用的内容,以便迁移是可逆的。

可选的hints参数将作为**hints传递到数据库路由器的allow_migrate()方法,以帮助他们做出路由决策。 有关数据库提示的更多详细信息,请参阅Hints

可选的elidable参数用于确定squashing migrations时是否删除(删除)操作。

建议您将代码写为迁移文件中Migration类上方的单独函数,并将其传递到RunPython 这里有一个使用RunPythonCountry模型上创建一些初始对象的示例:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations

def forwards_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    # if we directly import it, it'll be the wrong version
    Country = apps.get_model("myapp", "Country")
    db_alias = schema_editor.connection.alias
    Country.objects.using(db_alias).bulk_create([
        Country(name="USA", code="us"),
        Country(name="France", code="fr"),
    ])

def reverse_func(apps, schema_editor):
    # forwards_func() creates two Country instances,
    # so reverse_func() should delete them.
    Country = apps.get_model("myapp", "Country")
    db_alias = schema_editor.connection.alias
    Country.objects.using(db_alias).filter(name="USA", code="us").delete()
    Country.objects.using(db_alias).filter(name="France", code="fr").delete()

class Migration(migrations.Migration):

    dependencies = []

    operations = [
        migrations.RunPython(forwards_func, reverse_func),
    ]

这通常是您将用于创建data migrations,运行自定义数据更新和更改以及您需要访问ORM和/或Python代码的任何操作。

如果你从South升级,这基本上是南模式作为一个操作 - 一个或两个方法向前和向后,可用的ORM和模式操作。 大多数情况下,您应该能够翻译orm.Modelorm [“appname”, “Model”] 引用此处的apps.get_model(“appname”, “Model”)的数据迁移的代码不变。 但是,apps只会引用当前应用程序中的模型,除非将其他应用程序中的迁移添加到迁移的依赖关系中。

RunSQL很相似,请确保如果您在此处更改模式,则可以在Django模型系统范围之外(例如,触发器)或使用SeparateDatabaseAndState添加将反映您对模型状态的更改的操作,否则版本化的ORM和自动检测器将停止正常工作。

默认情况下,RunPython将在不支持DDL事务的数据库(例如MySQL和Oracle)上的事务内部运行其内容。 这应该是安全的,但如果您尝试使用这些后端提供的schema_editor,可能会导致崩溃;在这种情况下,将atomic=False传递给RunPython操作。

在支持DDL事务的数据库(SQLite和PostgreSQL)上,除了为每个迁移创建的事务之外,RunPython操作不会自动添加任何事务。 因此,在PostgreSQL上,您应该避免在相同的迁移中组合模式更改和RunPython操作,否则可能会导致类似错误 OperationalError: 不能 改变 “MYTABLE” 因为 具有 有待 触发 事件.

如果您有不同的数据库,并且不确定它是否支持DDL事务,请检查django.db.connection.features.can_rollback_ddl属性。

如果RunPython操作是non-atomic migration的一部分,那么只有在将atomic=True传递到RunPython操作。

警告

RunPython不会神奇地改变您的模型的连接;您调用的任何模型方法都将转到默认数据库,除非您给它们当前数据库别名(可从schema_editor.connection.alias获得,其中schema_editor是您的第二个参数功能)。

静态的 RunPython。noop()[source]

当希望操作在给定方向不执行任何操作时,将RunPython.noop方法传递到codereverse_code 这在使操作可逆时尤其有用。

Django中的新功能1.10:

添加了elidable参数。

在Django更改1.10:

atomic参数默认值更改为None,表示原子性由迁移的atomic属性控制。

SeparateDatabaseAndState

class SeparateDatabaseAndState(database_operations=None, state_operations=None)[source]

高度专业化的操作,允许您混合和匹配数据库(模式更改)和操作的状态(自动检测器供电)方面。

它接受两个操作列表,并且当被要求应用状态时将使用状态列表,并且当被要求对数据库应用更改时将使用数据库列表。 不要使用此操作,除非你非常确定你知道你在做什么。

编写自己的操作

操作有一个相对简单的API,它们的设计使您可以轻松地编写自己的内容来补充内置的Django。 Operation的基本结构如下所示:

from django.db.migrations.operations.base import Operation

class MyCustomOperation(Operation):

    # If this is False, it means that this operation will be ignored by
    # sqlmigrate; if true, it will be run and the SQL collected for its output.
    reduces_to_sql = False

    # If this is False, Django will refuse to reverse past this operation.
    reversible = False

    def __init__(self, arg1, arg2):
        # Operations are usually instantiated with arguments in migration
        # files. Store the values of them on self for later use.
        pass

    def state_forwards(self, app_label, state):
        # The Operation should take the 'state' parameter (an instance of
        # django.db.migrations.state.ProjectState) and mutate it to match
        # any schema changes that have occurred.
        pass

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        # The Operation should use schema_editor to apply any changes it
        # wants to make to the database.
        pass

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        # If reversible is True, this is called when the operation is reversed.
        pass

    def describe(self):
        # This is used to describe what the operation does in console output.
        return "Custom Operation"

尽管我们建议您参考django.db.migrations.operations中的内置Django操作,但可以轻松阅读并覆盖很多示例。使用迁移框架的半内部方面,如ProjectState以及用于获取历史模型的模式,以及ModelState以及用于突变state_forwards()

有些事情要注意:

  • 您不需要学习太多关于ProjectState来编写简单的迁移;只需知道它有一个apps属性,可以访问应用程序注册表(您可以在其中调用get_model)。

  • database_forwardsdatabase_backwards都会传递给他们两个状态;这些只是代表state_forwards方法应用的差异,但是为了方便和速度的原因而给予您。

  • 如果要在database_forwards()database_backwards()中的from_state参数中使用模型类或模型实例,则必须呈现模型状态使用clear_delayed_apps_cache()方法使相关模型可用:

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        # This operation should have access to all models. Ensure that all models are
        # reloaded in case any are delayed.
        from_state.clear_delayed_apps_cache()
        ...
    
    Django中的新功能1.11:

    此要求和clear_delayed_apps_cache()方法是新的。

  • database_backwards方法中的to_state较旧的状态;那就是一旦移民完成倒转,那将是现在的状态。

  • 您可能会在内置操作中看到references_model的实现;这是自动检测代码的一部分,与自定义操作无关。

警告

出于性能原因,ModelState.fields中的Field实例在迁移之间重复使用。 您绝对不能更改这些实例上的属性。 如果您需要在state_forwards()中更改字段,则必须从ModelState.fields中删除旧实例,并在其中添加一个新实例。 对于ModelState.managers中的Manager实例也是如此。

作为一个简单的例子,让我们做一个加载PostgreSQL扩展(它包含一些PostgreSQL的更令人兴奋的功能)的操作。 很简单没有模型状态更改,它所做的一切都是运行一个命令:

from django.db.migrations.operations.base import Operation

class LoadExtension(Operation):

    reversible = True

    def __init__(self, name):
        self.name = name

    def state_forwards(self, app_label, state):
        pass

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        schema_editor.execute("CREATE EXTENSION IF NOT EXISTS %s" % self.name)

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        schema_editor.execute("DROP EXTENSION %s" % self.name)

    def describe(self):
        return "Creates extension %s" % self.name