How to read environment variable from Apache upgrade from Django 1.6.5 to 1.7

I want to read environment variables from Apache vhost config file and store them in Django settings.

Everything was fine before upgrading to Django 1.7, but now it's broken.

The problem seems to be in my wsgi.py script when I call

_application = get_wsgi_application()

      

as it reads the config file before the environment variable is set.

Is there any other way to do this in Django 1.7?

In my / etc / apache 2 / sites-enabled / mysyte.conf, I have:

<VirtualHost *:80>

    ...

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

      

In my 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)

      

In my settings.py I have:

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')

...

      

This is what the log file says:

...
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
...

      

+3


source to share


1 answer


I'm afraid that what you are trying to do here is inherently fragile, only worked by lucky accident in previous versions of Django, and won't work with Django 1.7 or any future version of Django. ( Update : this will also make you potentially vulnerable to the "shellshock" bash error, whereas WSGI usually isn't.)

The main problem is that the WSGI framework is only available for every request, but you are trying to set the global config for your Django process based on that. This is inefficient and conceptually broken (why are you re-setting OS environment variables over and over every time a request comes in? What if different requests have a different WSGI environment?), And it can only work for everyone if Django is waiting to set itself up to those until the first request arrives.

But the unpredictable timing and order of the Django startup sequence in previous versions caused problems. For example, when using runerver in local development, Django will readily configure itself due to validation checks, but in a production environment it will lazily configure itself (which you rely on), which means sometimes imports will happen in a different order and loop imports will occur in production that are not playable under server-to-server.



Django 1.7 includes an updated startup sequence to address these issues, makes startup sequence predictable and consistent between development and production, and allows users to explicitly register code to run during startup (via AppConfig.ready()

). A side effect of this is that the settings are configured when your process starts (in particular when called django.setup()

in get_wsgi_application()

), without waiting for the first request.

If you are only running one Django site on that server, I would just move your configuration into normal environment variables, not SetEnv

your Apache configuration, and avoid the whole problem.

If you run multiple Django sites that require separate configuration through the same Apache server, this will not work. In this case, perhaps someone more familiar with Apache mod_wsgi

can give you tips on how to safely pass environment variables from your Apache configuration to your Django process; I personally found the process model (actually process models, since there is more than one there depends on how you set it up) is mod_wsgi

confusing and error prone when trying to run multiple independently configured sites through the same server. I find it easier to use a dedicated WSGI server like gunicorn or uwsgi and have an Apache (or nginx) proxy. Then it just starts several gunicorn / uwsgi processes with separate OS environments.

+4


source







All Articles