如何从Apache更新从Django 1.6.5到1.7更新环境变量

时间:2014-09-11 09:59:02

标签: django apache environment-variables django-wsgi django-1.7

我想从Apache vhost配置文件中读取环境变量并将它们存储到Django设置中。

在更新到Django 1.7之前,一切都很好,但现在已经坏了。

当我调用

时,问题出现在我的wsgi.py脚本中
_application = get_wsgi_application()

因为它在设置环境变量之前读取配置文件。

在Django 1.7中还有另一种方法吗?

在我的/etc/apache2/sites-enabled/mysyte.conf中我有:

<VirtualHost *:80>

    ...

    SetEnv SECRET_KEY ...
    SetEnv EMAIL_HOST ...
    SetEnv EMAIL_HOST_PASSWORD ...
    SetEnv EMAIL_HOST_USER ...
    SetEnv EMAIL_PORT 25
    ...

在我的wsgi.py中:

import os
from os.path import abspath, dirname
from sys import path

SITE_ROOT = dirname(dirname(abspath(__file__)))
path.append(SITE_ROOT)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "locacle.settings.production")

_application = get_wsgi_application()

def application(environ, start_response):
    for key, value in environ.items():
        if isinstance(environ[key], str):
            os.environ[key] = environ[key]

    return _application(environ, start_response)

在我的settings.py中,我有:

from os import environ

from base import *

def get_env_setting(setting):
    """ Get the environment setting or return exception """
    try:
        return environ[setting]
    except KeyError:
        error_msg = "Set the %s env variable" % setting
        raise ImproperlyConfigured(error_msg)


EMAIL_HOST = get_env_setting('EMAIL_HOST')

...

这是日志文件报告的内容:

...
mod = importlib.import_module(self.SETTINGS_MODULE)
File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
  __import__(name)
File "/home/www/.../settings/production.py", line 34, in <module>
  EMAIL_HOST = get_env_setting('EMAIL_HOST')
File "/home/www/...settings/production.py", line 21, in get_env_setting
  raise ImproperlyConfigured(error_msg)
ImproperlyConfigured: Set the EMAIL_HOST env variable
...

1 个答案:

答案 0 :(得分:4)

我担心你在这里尝试做的事情本质上是脆弱的,只能通过以前版本的Django上的幸运事故来工作,并且不适用于Django 1.7或任何未来版本的Django。 (更新:它也会让你容易受到“shellshock”bash bug的攻击,而WSGI通常不会。)

基本问题是WSGI环境仅在每个请求的基础上可用,但您正在尝试基于它为Django进程设置全局配置。这是低效的并且在概念上被破坏了(为什么每次请求进入时都会一次又一次地重新设置OS环境变量?如果不同的请求具有不同的WSGI环境会怎么样?)并且它只能在Django等待的时候才能工作配置自己,直到第一个请求到达。

但Django在以前版本中的启动顺序的不可预测的时间和顺序引起了问题。例如,当在本地开发中使用runserver时,由于验证检查,Django会急切地自行配置,但在生产环境下,它只能懒惰地配置它(你依赖它),这意味着有时候导入会以不同的顺序发生,生产中的循环进口将在runserver下无法重现。

Django 1.7包含一个改进的启动序列,以解决这些问题,使启动序列在开发和生产之间可预测和一致,并允许用户显式注册代码以在启动时运行(通过AppConfig.ready())。这样做的副作用是在您的流程启动时配置设置(特别是在django.setup()中调用get_wsgi_application()),而不是等到第一个请求进入。

如果您只在此服务器上运行一个Django站点,我只需将您的配置移动到普通环境变量而不是Apache配置中的SetEnv,并避免整个问题。

如果您正在运行多个Django站点,这些站点需要通过单个Apache服务器进行不同的配置,那么这将无效。在这种情况下,也许更熟悉Apache和mod_wsgi的人可以为您提供有关如何以可靠的方式将环境变量从Apache配置传递到Django进程的建议;在尝试通过一台服务器运行多个独立配置的站点时,我个人发现了mod_wsgi混淆且容易出错的流程模型(实际上是流程模型,因为根据配置方式不止一个)。我发现使用像gunicorn或uwsgi这样的专用WSGI服务器并使用Apache(或nginx)代理更简单。然后,使用单独的操作系统环境运行多个gunicorn / uwsgi进程非常简单。