在Django中进行迁移条件

时间:2015-08-05 11:17:52

标签: django postgresql django-migrations django-1.8

具体用例是:

  

A Django module想要在迁移期间创建扩展程序。如果   用于运行迁移的数据库用户不是超级用户,这个   失败。

有几种方法可以解决这个问题,一种方法(假设)检查迁移文件是否安装了扩展,如果没有安装则只运行该SQL代码。

然而,经过一些研究,似乎Django的RunSQL不能返回结果,并且随后根据先前操作的结果排除操作是不可能的。有没有其他方法可以实现这一目标? (例如,继承RunSQL?)

任何基于Django迁移,Django设置或Postgres内部的解决方案(只有在某个条件为真时才能运行CREATE EXTENSION的一个SQL语句)都可以。

(请注意,我提到django-pgcrypto-fields只是为了说明。我有兴趣知道这种解决方案是否一般存在。)

编辑回答Anentropic的评论: 运行testjenkins命令时,解决方案必须正常工作。这意味着,手动调用--fake-initial或类似操作以避免运行此迁移不是一种选择。如果您可以解释如何使test伪造某些迁移,那么这是非常受欢迎的。

我目前的解决方案是将以下内容添加到settings

MIGRATION_MODULES = {
    'pgcrypto_fields': 'do-not-run-migrations'
}

但这会禁用所有有问题的迁移,而不仅仅是违规迁移。在这种情况下,它可能会起作用,但我认为这是一个幸运和丑陋的工作。

1 个答案:

答案 0 :(得分:0)

实际上,Django的HStoreExtension只在必要时运行。但当然,它仍然需要超级用户访问权限。对于pgcrypto,可以创建类似于HStoreExtension的类。

使其在测试中运行的设置仍然需要超级用户访问权限,因此设置必须如下所示:

INSTALLED_APPS = (
    ...
    'django.contrib.postgres',
    ...
)

if sys.argv[1] in ['test', 'jenkins']:
    # Install extension hstore (requires superuser)
    INSTALLED_APPS = ('test_init',) + INSTALLED_APPS

    # a superuser
    DATABASES["default"]["USER"] = 'xxx'
    DATABASES["default"]["PASSWORD"] = 'xxx'

并且'test_init'django应用程序仅包含必需的__init.py__以及包含以下文件0001_initial.py的迁移模块:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.postgres.operations import HStoreExtension

from django.db import migrations


class Migration(migrations.Migration):

    run_before = [
        ('some_app_that_requires_hstore', '0001_initial'),
    ]

    operations = [
        HStoreExtension(),
    ]

实际上不需要检查测试模式(通过sys.argv)来进行迁移。如上所述,HStoreExtension对错误保持沉默。因此,即使您在没有超级用户的情况下在生产中运行migrate,也不会失败,无论是否安装了hstore。查看其源代码。

另见Django's documentation of HStoreField