从Django wsgi.py文件访问Apache SetEnv变量

Nel*_*luk 15 apache django ubuntu

我正在尝试将Django的密钥和DB传递给环境变量,正如广泛建议的那样,因此我可以在本地/生产服务器之间使用相同的代码库.

我遇到的问题是正确设置然后在运行Apache + mod_wsgi的生产服务器上读取环境变量.

我的用户配置文件中设置的Vars不可用,因为Apache不是以该用户身份运行的.虚拟主机文件中设置的SetEnv变量不可用,因为范围有所不同.

我读过一对夫妇1,2 SO答案,从而导致这个博客用的解决方案.

我无法弄清楚如何将解决方案应用于使用wsgi.py文件的当前版本的Django,如下所示:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Run Code Online (Sandbox Code Playgroud)

我如何将该博客解决方案应用于wsgi.py文件,或者是否有更好的地方存储Django可以获取的env-vars?

Abe*_*ler 22

如果其他人对格雷厄姆的回答感到沮丧,那么这个解决方案实际上适用于原始问题.我个人发现从Apache设置环境变量是非常有用和实用的,特别是因为我配置了自己的托管环境,可以做任何我想做的事情.

wsgi.py(在Django 1.5.4中测试)

from django.core.handlers.wsgi import WSGIHandler

class WSGIEnvironment(WSGIHandler):

    def __call__(self, environ, start_response):

        os.environ['SETTINGS_CONFIG'] = environ['SETTINGS_CONFIG']
        return super(WSGIEnvironment, self).__call__(environ, start_response)

application = WSGIEnvironment()
Run Code Online (Sandbox Code Playgroud)

小记,你失去了面向未来的方法django.core.wsgi.get_wsgi_application,目前只返回WSGIHandler().如果该WSGIHandler.__call__方法已更新并且您也更新了Django,则可能必须WSGIEnvironment在参数更改时更新该类.我认为这是一个非常小的罚款,以支付方便.

  • @Izkata你能举一个更新的做事方式的完整例子吗? (2认同)

Gra*_*ton 10

FWIW.依赖环境变量进行细粒度配置设置通常不是一个好主意.这是因为并非所有WSGI托管环境或商业PaaS产品都支持该概念.使用环境变量进行细粒度设置还可以有效地将您锁定到特定的PaaS产品中,您可以直接在代码中直接嵌入查找特定命名的环境变量,其中该环境变量的命名约定特定于该托管服务.因此,尽管某些服务推动了环境变量的使用,但要始终注意依赖于环境变量,因为它会降低WSGI应用程序的可移植性,并使部署机制之间的移动变得更加困难.

总而言之,您提到的博客文章通常不会有所帮助.这是因为它正在使用令人讨厌的技巧,即根据在Apache中使用SetEnv设置的每个请求WSGI环境设置在每个请求上设置进程环境变量.如果环境变量的值可能因URL上下文而异,则可能会在多线程配置中导致各种问题.对于Django的情况,它没有用,因为Django设置模块通常会在处理任何请求之前导入,这意味着环境变量在所需的时间不可用.

整个部署配置区域迫切需要一种更好的处理方式,但坦率地说,它主要是一个失败的原因,因为托管服务不会改变以适应更好的WSGI部署策略.他们已经完成了他们的工作,让他们的客户已经锁定他们已经完成的工作方式,并且即使存在更好的方法,也不会为自己创造工作并改变事物.

无论如何,"计算机科学中的所有问题都可以通过另一层次的间接解决".(http://en.wikipedia.org/wiki/Indirection)这就是你在这里可以做的.

没有应用程序查找环境变量.让它导入特定于部署的Python配置模块,其中包含使用API​​获取配置设置的方法.该配置模块将基于部署机制实现获取实际设置的不同方式.在某些情况下,它可以从环境变量中获取值.对于其他例如Apache/mod_wsgi,值可以在该配置模块中,或者从单独的配置文件中读取,该文件可以是ini,json或yaml格式.在提供API时,它还可以将配置设置的名称映射到不同PaaS产品使用的不同名称.

此配置模块不需要是应用程序代码的一部分,但可以手动放入目标系统上的"/ etc /"子目录中.然后,您需要设置Python模块搜索路径,以便您的应用程序可以看到它.作为更广泛的WSGI部署标准的一部分,整个系统可以做得相当优雅,但正如我所说,当现有的PaaS产品极不可能改变使用这样的标准时,很少有动力去创造这样的事情. .


Fel*_*ipe 5

这是一种替代解决方案,可以满足未来需求get_wsgi_application.它甚至允许您设置要在Django初始化中使用的环境变量.

# in wsgi.py

KEYS_TO_LOAD = [
    # A list of the keys you'd like to load from the WSGI environ
    # into os.environ
]

def loading_app(wsgi_environ, start_response):
    global real_app
    import os
    for key in KEYS_TO_LOAD:
        try:
            os.environ[key] = wsgi_environ[key]
        except KeyError:
            # The WSGI environment doesn't have the key
            pass
    from django.core.wsgi import get_wsgi_application
    real_app = get_wsgi_application()
    return real_app(wsgi_environ, start_response)

real_app = loading_app

application = lambda env, start: real_app(env, start)
Run Code Online (Sandbox Code Playgroud)

我不是100%清楚如何mod_wsgi管理它的进程,但我认为它不会经常重新加载WSGI应用程序.如果是这样,初始化Django的性能损失只会在第一个请求中发生一次.

或者,如果在初始化Django之前不需要设置环境变量,则可以使用以下命令:

# in wsgi.py

KEYS_TO_LOAD = [
    # A list of the keys you'd like to load from the WSGI environ
    # into os.environ
]

from django.core.wsgi import get_wsgi_application
django_app = get_wsgi_application()

def loading_app(wsgi_environ, start_response):
    global real_app
    import os
    for key in KEYS_TO_LOAD:
        try:
            os.environ[key] = wsgi_environ[key]
        except KeyError:
            # The WSGI environment doesn't have the key
            pass
    real_app = django_app
    return real_app(wsgi_environ, start_response)

real_app = loading_app

application = lambda env, start: real_app(env, start)
Run Code Online (Sandbox Code Playgroud)