【Django文档转译】第2章:模型层——第2节:迁移(模块7: 操作参考)

迁移行动¶

迁移文件由一个或多个文件组成。Operation以声明方式记录迁移应该对数据库做什么的对象。

Django也使用这些Operation对象来计算模型的历史外观,并计算自上次迁移以来对模型所做的更改,以便自动编写迁移;这就是它们具有声明性的原因,因为这意味着Django可以轻松地将它们加载到内存中,并在不接触数据库的情况下运行它们,从而确定项目的外观。

还有更专业的Operation对象,这些对象用于以下内容:数据迁移以及高级手工数据库操作。你也可以自己写Operation类,如果您希望封装您通常进行的自定义更改,则为。

如果您需要一个空迁移文件来编写您自己的Operation对象进入,只需使用python manage.py makemigrations --empty yourappname,但请注意,手动添加模式更改操作可能会混淆迁移自动检测器,并导致makemigrations输出错误的代码。

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

有关介绍性材料,请参阅迁移主题指南.

模式操作¶

CreateModel¶

班级CreateModel(名字, 田, 选项=无, 碱基=无, 管理人员=无)[源代码]¶
在项目历史记录中创建一个新模型,并在数据库中创建相应的表来匹配它。

名字是模型名称,如在models.py档案。

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

备选方案是来自模型的值的可选字典Meta班级。

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

管理人员的两个元组的列表。(manager_name, manager_instance)…列表中的第一个管理器将是迁移期间该模型的默认管理器。

DeleteModel¶

班级DeleteModel(名字)[源代码]¶
从项目历史记录中删除模型,并从数据库中删除其表。

RenameModel¶

班级RenameModel(旧名, 新名称)[源代码]¶
将模型从旧名称重命名为新名称。

如果同时更改模型的名称及其许多字段,则可能必须手动添加此内容;在自动检测器中,这将看起来就像删除了一个旧名称的模型,并添加了一个新的名称不同的模型,并且它创建的迁移将丢失旧表中的任何数据。

AlterModelTable¶

班级AlterModelTable(名字, 表)[源代码]¶
更改模型的表名(db_table选项的Meta(子类)。

AlterUniqueTogether¶

班级AlterUniqueTogether(名字, 独树一帜)[源代码]¶
更改模型的唯一约束集(独树一帜选项的Meta(子类)。

AlterIndexTogether¶

班级AlterIndexTogether(名字, 综合指数)[源代码]¶
更改模型的自定义索引集(综合指数选项的Meta(子类)。

AlterOrderWithRespectTo¶

班级AlterOrderWithRespectTo(名字, 对……有尊重的命令)[源代码]¶
创建或删除_order类所需的列。对……有尊重的命令选项的Meta子类。

AlterModelOptions¶

班级AlterModelOptions(名字, 备选方案)[源代码]¶
存储对杂项模型选项的更改(模型上的设置)Meta)就像permissions和verbose_name…不影响数据库,但将这些更改保存到RunPython要使用的实例。备选方案应该是将选项名映射到值的字典。

AlterModelManagers¶

班级AlterModelManagers(名字, 管理人员)[源代码]¶
更改迁移期间可用的管理器。

AddField¶

班级AddField(型号名称, 名字, 场域, 保存默认值=True)[源代码]¶
将字段添加到模型中。型号名称是模特的名字,名字字段的名称,以及场域是一个未绑定的字段实例(您将在models.py-例如,models.IntegerField(null=True).

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

RemoveField¶

班级RemoveField(型号名称, 名字)[源代码]¶
从模型中移除字段。

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

AlterField¶

班级AlterField(型号名称, 名字, 场域, 保存默认值=True)[源代码]¶
更改字段的定义,包括对其类型的更改,null, unique, db_column以及其他字段属性。

这个preserve_default参数指示该字段的默认值是否为永久值,是否应放入项目状态(True),或者如果它是临时的,并且仅用于这种迁移(False)–通常是因为迁移将可空字段更改为非空字段,并且需要一个默认值才能将其放入现有行中。它不会直接影响在数据库中设置默认值的行为-Django从不设置数据库默认值,并且总是在Django ORM代码中应用它们。

请注意,并非所有数据库上的更改都是可能的,例如,您不能更改类似的文本类型字段。models.TextField()进入一个数字类型字段,如models.IntegerField()在大多数数据库中。

RenameField¶

班级RenameField(型号名称, 旧名, 新名称)[源代码]¶
更改字段的名称(并且,除非db_column设置它的列名)。

AddIndex¶

班级AddIndex(型号名称, 指数)[源代码]¶
为模型创建数据库表中的索引。型号名称. 指数是Index班级。

RemoveIndex¶

班级RemoveIndex(型号名称, 名字)[源代码]¶
移除名为名字从模型中型号名称.

特别行动¶

RunSQL¶

班级RunSQL(SQL, 反向SQL=无, 状态操作=无, 提示=无, 可撤销=假)[源代码]¶
允许在数据库上运行任意SQL–对于Django不直接支持的数据库后端的更高级特性非常有用,比如部分索引。

SQL,和reverse_sql如果提供,则应该是要在数据库上运行的SQL字符串。在大多数数据库后端(PostgreSQL除外)上,Django将在执行SQL之前将SQL拆分为单独的语句。这需要安装平方解析Python库。

您还可以传递字符串或二元组的列表。后者用于传递查询和参数,其方式与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()数据库路由器的方法,以帮助他们作出路由决策。看见提示有关数据库提示的详细信息。

任选elidable参数确定操作是否将在下列情况下被移除(省略)。压扁迁徙.

RunSQL.noop¶

通过RunSQL.noop属性为SQL或reverse_sql当您希望操作不要在给定的方向上做任何事情时。这对于使操作可逆特别有用。

RunPython¶

班级RunPython(电码, 反向代码=无, 原子=无, 提示=无, 可撤销=假)[源代码]¶
在历史上下文中运行自定义Python代码。电码(和reverse_code如果提供的话)应该是接受两个参数的可调用对象;第一个是django.apps.registry.Apps包含与项目历史记录中操作位置匹配的历史模型,第二个模型是SchemaEditor.

这个reverse_code参数在不应用迁移时调用。此可调用项应撤消在电码可调用以便迁移是可逆的。

任选hints参数将作为**hints到allow_migrate()数据库路由器帮助他们做出路由决策的方法。看见提示有关数据库提示的详细信息。

任选elidable参数确定操作是否将在下列情况下被移除(省略)。压扁迁徙.

建议您将代码编写为Migration类,并将其传递给RunPython…下面是一个使用RunPython若要在Country模型:

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),
    ]

这通常是用来创建数据迁移,运行自定义数据更新和更改,以及您需要访问ORM和/或Python代码的任何其他内容。

如果您是从南方升级,这基本上是作为一个操作南方模式-一个或两个方法向前和向后,一个ORM和模式操作可用。大多数情况下,您应该能够翻译orm.Model或orm[“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: cannot ALTER TABLE “mytable” because it has pending trigger events.

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

如果RunPython操作是非原子迁移,则该操作将仅在以下情况下在事务中执行:atomic=True传递给RunPython行动。

警告

RunPython不会神奇地为您更改模型的连接;您调用的任何模型方法都将转到默认数据库,除非您为它们提供当前的数据库别名(可从schema_editor.connection.alias,在哪里schema_editor是函数的第二个参数)。

静态RunPython.noop()[源代码]¶

通过RunPython.noop方法电码或reverse_code当您希望操作不要在给定的方向上做任何事情时。这对于使操作可逆特别有用。

SeparateDatabaseAndState¶

班级SeparateDatabaseAndState(数据库操作=无, 状态操作=无)[源代码]¶
一种高度专业化的操作,允许您混合和匹配操作的数据库(模式更改)和状态(自动检测-供电)方面。

它接受两个操作列表,当被要求应用状态时,状态将使用状态列表,当被要求对数据库应用更改时将使用数据库列表。除非你确信自己知道自己在做什么,否则不要使用这个操作。

自己写¶

操作有一个相对简单的API,它们的设计使您可以轻松地编写自己的API来补充内置Django的API。的基本结构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-它们易于阅读,并且涵盖了迁移框架的半内部方面的许多示例用法,如ProjectState以及用于获取历史模型的模式,以及ModelState中用于突变历史模型的模式。state_forwards().

有些事情要注意:

你不需要学太多ProjectState只需编写简单的迁移;只需知道它有一个apps属性,该属性提供对应用程序注册表的访问(然后您可以调用该属性)。get_model)。

database_forwards和database_backwards两种状态都被传递给它们;它们只是表示state_forwards方法本来可以应用,但由于方便和速度的原因而提供给您。

如果要使用模型类或模型实例,请从from_state争论database_forwards()或database_backwards(),则必须使用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()
    ...

to_state在数据库_后退方法中,老一点状态;也就是说,在迁移完成反转后,状态将是当前状态。

您可能会看到references_model在内置操作上;这是自动检测代码的一部分,对于自定义操作并不重要。

警告

出于性能原因,Field实例ModelState.fields在迁移过程中被重用。决不能更改这些实例的属性。如果您需要在state_forwards(),则必须将旧实例从ModelState.fields并在其位置添加一个新实例。同样的情况也适用于Manager实例ModelState.managers.

作为一个简单的例子,让我们进行一个加载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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值