具体用例是:
A Django module想要在迁移期间创建扩展程序。如果 用于运行迁移的数据库用户不是超级用户,这个 失败。
有几种方法可以解决这个问题,一种方法(假设)检查迁移文件是否安装了扩展,如果没有安装则只运行该SQL代码。
然而,经过一些研究,似乎Django的RunSQL
不能返回结果,并且随后根据先前操作的结果排除操作是不可能的。有没有其他方法可以实现这一目标? (例如,继承RunSQL
?)
任何基于Django迁移,Django设置或Postgres内部的解决方案(只有在某个条件为真时才能运行CREATE EXTENSION
的一个SQL语句)都可以。
(请注意,我提到django-pgcrypto-fields只是为了说明。我有兴趣知道这种解决方案是否一般存在。)
编辑回答Anentropic的评论:
运行test
或jenkins
命令时,解决方案必须正常工作。这意味着,手动调用--fake-initial
或类似操作以避免运行此迁移不是一种选择。如果您可以解释如何使test
伪造某些迁移,那么这是非常受欢迎的。
我目前的解决方案是将以下内容添加到settings
:
MIGRATION_MODULES = {
'pgcrypto_fields': 'do-not-run-migrations'
}
但这会禁用所有有问题的迁移,而不仅仅是违规迁移。在这种情况下,它可能会起作用,但我认为这是一个幸运和丑陋的工作。
答案 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。查看其源代码。