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】:这是我解决问题的方法,因为我无法让 RunSQL
在 RunPython
中工作。幸运的是,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