【问题标题】:Python fabric "local" function does not respect environment variable DJANGO_SETTINGS_MODULEPython结构“本地”功能不尊重环境变量DJANGO_SETTINGS_MODULE
【发布时间】:2012-11-11 16:43:53
【问题描述】:

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

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_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_MODULE 和 为什么settings_module 不像宣传的那样工作。

【问题讨论】:

  • 我无法重现该问题。环境变量 DJANGO_SETTINGS_MODULE 和 settings_module 对我有用。你使用 Django 1.4 吗?你能在不同的机器上重现它吗?
  • @hynekcer 当你说你无法重现问题时,我认为你有一个与我类似的settings 方案,而不是一个简单的settings.py?是的,我有 django 1.4 和最新的 pip 可安装结构。
  • 是的,配置myproject/settings/anyfile.py,一个空的myproject/settings/__init__.py和和你一样的fabfile.py。
  • @hynekcer 将尝试在不同的系统上重现并回复您。

标签: python django deployment fabric


【解决方案1】:

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

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

【讨论】:

  • 感谢您的回答。我知道我可以做到这一点,我会更新我的问题以反映这一点。但基本上我想知道local 函数到底发生了什么,以及为什么settings_module 函数不能像宣传的那样工作。要么我做错了,要么它有错误。
  • 阅读我的回答了解更多详情。我赞成您的回答,因为这是规避此问题的方法之一。
【解决方案2】:

嗯,我发现了问题,但我不知道该怎么做。

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

虽然我的 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.pyDJANGO_SETTINGS_MODULE(发生在 deployment/fabric/database.py 中)的设置不会保留。

起初我错误地意识到os.environ 操作不会持续存在 跨模块!但这不是真的,因为我立即构建了一个类似的场景 在我的 django 项目之外并使我的错误前提无效。

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

不知道是不是跟fabric的魔法任务导入有关系 基本我不掌握,但以下任何一种方法都可以解决问题。

1)使用prefix上下文管理器

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

2)local 命令中附加一个--settings 值(如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')

【讨论】:

    猜你喜欢
    • 2019-07-12
    • 2012-08-23
    • 2017-01-01
    • 2012-07-14
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    相关资源
    最近更新 更多