Python结构“本地”功能不尊重环境变量DJANGO_SETTINGS_MODULE

时间:2012-11-11 16:43:54

标签: python django deployment fabric

我的项目设置有以下方案:

myproject/
   app1/
   app2/
   appN/
   settings/
      __init__.py
      base.py
      devel.py
      production.py

在我的本地环境中,我有virtualenvwrapper的postactivate脚本:

myproject_root=/home/rantanplan/Projects/repos/myproject
cd $myproject_root
export DJANGO_SETTINGS_MODULE=myproject.settings.devel

因此,当我workon myproject时,它将更改为项目的根目录和 设置我想要的有效DJANGO_SETTINGS_MODULE

这对于django和所有命令(如python manage.py syncdb)都可以。

另一方面,我有这个结构任务:

@task
def syncdb():
    local('python manage.py syncdb --noinput')

当我有一个简单的settings.py文件时,这曾经很好用,但是当我改变时 对于上述方案,它提出了这个例外:

django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.

Fatal error: local() encountered an error (return code 1) while executing 'python manage.py syncdb --noinput'

Aborting.

一些补充说明:

  • project函数在这里不适用,因为它错误地假设(内部)所有django设置模块都被命名为“settings”。
  • 我尝试了settings_module功能无济于事。它在内部使用os.environ来设置环境变量但不起作用。
  • 如果我在任务定义之前打印os.environ['DJANGO_SETTINGS_MODULE'],它会正确打印“myproject.settings.devel”。

那我在这里做错了什么,你怎么建议我应该解决这个问题?


为了免除我应该说的麻烦,我知道我可以通过以下方式解决这个问题:

def syncdb():
    with prefix('export DJANGO_SETTINGS_MODULE=myproject.settings.devel'):
        local('python manage.py syncdb --noinput')

但如果可以,我宁愿避免使用prefix

我也知道我能做到,正如hynekcer建议的那样:

@task
def syncdb():
    local('python manage.py syncdb --settings=myproject.settings.devel --noinput')

但我真的想知道为什么local不尊重DJANGO_SETTINGS_MODULEsettings_module 为什么{{1}}不像宣传的那样有效。

2 个答案:

答案 0 :(得分:1)

您可以使用settings选项。它优先于DJANGO_SETTINGS_MODULE变量。

@task
def syncdb():
    local('python manage.py syncdb --settings=myproject.settings.devel --noinput')

答案 1 :(得分:1)

我找到了问题,但我不知道该怎么做。

首先,似乎我没有透露所有必要的信息。

虽然我的django项目的结构与我描述的完全一样,但我的面料 结构有点复杂。

本质上,我遵循this part of fabric's documentation

中的一些模式

完整的结构如下所述:

deployment/
  __init__.py
  fabric/
    __init__.py
    database.py
    repo.py
    services.py
myproject/
  app1/
  app2/
  appN/
manage.py
fabfile.py

deployment/fabric/database.py内我有这段代码:

django.settings_module('myproject.settings.devel')

@task
def syncdb():
    local('python manage.py syncdb --noinput')

fabfile.py我的所有进口货物中

from deployment.fabric.database import dropdb, createdb, syncdb, createuser
from deployment.fabric.something import blahblah

由于某些原因,我现在似乎无法掌握fabfile.py内部 DJANGO_SETTINGS_MODULE的设置(在deployment / fabric / database.py中发生)不会保留。

起初我意识到os.environ行为不会持续存在 跨模块!但事实并非如此,因为我立即构建了类似的场景 在我的django项目之外,并使我的错误前提无效。

然后我检查了fabric的local函数,发现它本质上是一个包装器 超过subprocess.Popen('...', shell=True)。所以我测试了我之前的实验 使用subprocess.Popen并且它仍然保留模块之间的环境变量。

我不知道它是否与面料的魔术任务导入有关,或者有什么东西 基本的我没有掌握,但以下任何方法都将解决问题。

1)使用prefix上下文管理器

def syncdb():
    with prefix('export DJANGO_SETTINGS_MODULE=myproject.settings.devel'):
        local('python manage.py syncdb --noinput')

2)--settings命令中附加local值(如hynekcer所述)

@task
def syncdb():
    local('python manage.py syncdb --settings=myproject.settings.devel --noinput')

3)在任务中包含settings_module调用(虽然它有点无效)。

@task
def syncdb():
    django.settings_module('myproject.settings.devel')
    local('python manage.py syncdb --noinput')