3

我想从 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
...
4

1 回答 1

4

恐怕您在这里尝试做的事情本质上是脆弱的,只能在以前版本的 Django 上幸运地工作,并且不适用于 Django 1.7 或任何未来版本的 Django。(更新:它还可能使您容易受到“shellshock” bash 错误的影响,而 WSGI 通常不会。)

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

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

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

如果你只在这台服务器上运行一个 Django 站点,我会简单地将你的配置移动到正常的环境变量中,而不是SetEnv在你的 Apache 配置中,并避免整个问题。

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

于 2014-09-12T17:07:40.070 回答