Django Migration RunSQL 以数据库类型为条件

Posted

技术标签:

【中文标题】Django Migration RunSQL 以数据库类型为条件【英文标题】:Django Migration RunSQL Conditional on Database Type 【发布时间】:2015-11-29 19:33:18 【问题描述】:

我正在尝试使用migrations.RunSQL Django 迁移来运行一些任意 SQL 代码。我只想为某些数据库后端(例如仅用于 postgres)运行此迁移。

我认为to use something like this 但我在Migration 类中看不到数据库连接信息。

【问题讨论】:

【参考方案1】:

这是我解决问题的方法,因为我无法让 RunSQLRunPython 中工作。幸运的是,schema_editor 对象有一个 execute() method。

def forwards(apps, schema_editor):
    if not schema_editor.connection.vendor.startswith('postgres'):
        logger.info('Database vendor: '.format(schema_editor.connection.vendor))
        logger.info('Skipping migration without attempting to ADD CONSTRAINT')
        return

    schema_editor.execute('ALTER TABLE my_table ADD CONSTRAINT my_constraint (my_field != \'NaN\';)')


def backwards(apps, schema_editor):
    if not schema_editor.connection.vendor.startswith('postgres'):
        logger.info('Database vendor: '.format(schema_editor.connection.vendor))
        logger.info('Skipping migration without attempting to DROP CONSTRAINT')
        return

    schema_editor.execute('ALTER TABLE my_table DROP CONSTRAINT my_constraint;')


class Migration(migrations.Migration):

    dependencies = [
        ...
    ]

    operations = [
        migrations.RunPython(forwards, backwards, atomic=True)
    ]

【讨论】:

这对我有用,但我需要 atomic=False 小心atomic=False。如果某些操作成功而其他操作失败,您的数据库最终可能会处于不一致的状态。 否则 Django 会拒绝为我运行它。 atomic=False 必须至少在 mysql 和 Oracle 上使用,请参阅 docs.djangoproject.com/en/3.0/ref/migration-operations/…【参考方案2】:

我只是有同样的需要。我必须编辑一个设置序列初始值的迁移,它适用于 postgres 但不适用于 sqlite。这是我按照 Daniel 链接到的文档将 RunSQL 包装在 RunPython 中的方法。

from django.db import migrations


def forwards(apps, schema_editor):
    if not schema_editor.connection.vendor == 'postgres':
        return
    migrations.RunSQL(
        "alter sequence api_consumer_id_seq restart with 1000500;")


class Migration(migrations.Migration):
    dependencies = [
        ('api', '0043_auto_20160416_2313'),
    ]

    operations = [
        migrations.RunPython(forwards),
    ]

【讨论】:

我的供应商字符串是 postgresql 而不是 postgres(在 Django 1.10.6 中) 这个问题是migrations.RunSQL()返回一个对象。在使用某些参数调用该对象的 _run_sql() 方法之前,它实际上不会执行任何 SQL。有关同样使用migrations.RunPython() 方法但以实际执行 SQL 的方式执行 SQL 的解决方案,请参阅 PaulMest 的响应。【参考方案3】:

我今天解决了一个类似的问题——需要执行迁移以创建新模型,但仅适用于 postgres 数据库——我发现了这个问题。但是,马修的回答对我没有帮助。事实上,我不确定它是否有效。那是因为migrations.RunSQL(...) 的行实际上并没有运行 SQL;它创建一个RunSQL类型的新对象,它是一个Command,然后立即丢弃它。

这是我最终解决问题的方法,以防将来有人尝试搜索“django 条件迁移”:

from __future__ import unicode_literals

import django.contrib.postgres.fields
from django.db import migrations, models


class PostgresOnlyCreateModel(migrations.CreateModel):
    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        if schema_editor.connection.vendor.startswith("postgres"):
            super(PostgresOnlyCreateModel, self).database_forwards(app_label, schema_editor, from_state, to_state)

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        if schema_editor.connection.vendor.startswith("postgres"):
            super(PostgresOnlyCreateModel, self).database_backwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ...whatever...
    ]

    operations = [
        PostgresOnlyCreateModel(
            name='...whatever...',
            fields=[...whatever...],
        ),
    ]

【讨论】:

【参考方案4】:

Migration 类中没有提供该信息,它在传递给 RunPython 操作的schema_editor 属性中提供。有关使用此功能的一些示例,请参阅 the documentation。

【讨论】:

【参考方案5】:

另一种选择是让实际的 sql 依赖于 db.connection.vendor:

from django.db import connection

CONCURRENTLY = "CONCURRENTLY" if connection.vendor == "postgres" else ""
SQL = f"CREATE INDEX CONCURRENTLY..."

此时您可以只使用migrations.RunSQL,这很方便,特别是如果您使用state_operations 参数。

【讨论】:

以上是关于Django Migration RunSQL 以数据库类型为条件的主要内容,如果未能解决你的问题,请参考以下文章

[Django][Python]Django重置Migration

[Django][Python]Django重置Migration

PyTest-Django 在缺少 django_migration 表时失败

[python][django学习篇][4]django完成数据库代码翻译:迁移数据库(migration)

Django Migration (makemigrations) 应该与创建模型分开提交吗?

替换django的user模型出现的异常django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.00