2013-11-03 2 views
15

Django의 비밀 키와 DB 패스를 환경 변수로 분리하려고합니다. 따라서 로컬/프로덕션 서버간에 동일한 코드 기반을 사용할 수 있습니다.Django wsgi.py 파일에서 Apache SetEnv 변수에 액세스

내가 겪고있는 문제는 올바르게 설정하고 Apache + mod_wsgi를 실행하는 프로덕션 서버에서 환경 변수를 읽는 것입니다.

Apache가 해당 사용자로 실행되지 않았기 때문에 내 사용자 프로필에 설정된 Vars를 사용할 수 없습니다. 범위가 어떻게 든 다르기 때문에 SetEnv으로 가상 호스트 파일에 설정된 Vars를 사용할 수 없습니다.

저는 1, 2의 SO 답변을 읽었습니다. 해결책은 this blog입니다.

나는처럼 보이는 wsgi.py 파일을 사용 장고의 현재 버전에 솔루션을 적용하는 방법을 알아낼 수 없습니다 : 나는 어떻게 적용 할 수 있는지

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

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

그 wsgi.py 파일을 블로그 솔루션 장고가 얻을 수있는 env-vars를 저장하기에 더 좋은 곳이 있습니까?

답변

10

FWIW. 세밀한 구성 설정을위한 환경 변수에 의존하는 것은 일반적으로 좋은 생각이 아닙니다. 이는 모든 WSGI 호스팅 환경이나 상용 PaaS 제품이이 개념을 지원하지 않기 때문입니다. 세분화 된 설정에 환경 변수를 사용하면 특정 환경 변수의 조회를 코드에 직접 임베드 한 특정 PaaS 오퍼링에 효과적으로 잠길 수 있습니다.이 환경 변수의 명명 규칙은 해당 호스팅 서비스에만 해당됩니다. 따라서 환경 변수 사용이 특정 서비스에 의해 추진 되더라도 항상 WSGI 응용 프로그램의 이식성을 감소시키고 배포 메커니즘간에 이동하기가 더 어려워 지므로 환경 변수에 의존하는 것에주의하십시오.

그 모두가 말한 블로그 게시물은 일반적으로 도움이되지 않습니다. 이는 Apache에서 SetEnv를 사용하여 설정된 요청 당 WSGI 환경 설정을 기반으로 각 요청에서 프로세스 환경 변수를 설정하는 불쾌한 속임수를 사용하기 때문입니다. 환경 변수의 값이 URL 컨텍스트에 따라 다를 수있는 경우 다중 스레드 구성에서 다양한 문제가 발생할 수 있습니다. Django의 경우 요청이 처리되기 전에 Django 설정 모듈이 일반적으로 가져 오기 때문에 유용하지 않습니다. 즉, 환경 변수를 필요한 시간에 사용할 수 없다는 것을 의미합니다.

이 전체 배포 구성 영역에서는 작업을 수행하는 더 나은 방법이 절실히 필요하지만 사실 솔직히 호스팅 서비스는 WSGI 배포 전략을 개선하기 위해 변경되지 않기 때문에 대부분 잃어버린 원인입니다. 그들은 일을 끝내고 고객이 이미 해왔 던 방식으로 고객을 확보하게하고 더 나은 방법이 존재한다고해도 스스로 일을 만들고 변화 시키려하지 않습니다.

어쨌든 '컴퓨터 과학의 모든 문제는 다른 수준의 간접 지정으로 해결할 수 있습니다.' (http://en.wikipedia.org/wiki/Indirection) 여기까지 할 수 있습니다.

응용 프로그램 조회 환경 변수가 없습니다. API를 사용하여 구성 설정을 가져 오는 방법이 포함 된 배포 관련 Python 구성 모듈을 가져 오십시오. 이 구성 모듈은 배포 메커니즘을 기반으로 실제 설정을 가져 오는 여러 가지 방법을 구현합니다. 경우에 따라 환경 변수에서 값을 가져올 수도 있습니다. Apache/mod_wsgi와 같은 기타의 경우 값은 해당 구성 모듈에 있거나 ini, json 또는 yaml 형식 일 수있는 별도의 구성 파일에서 읽을 수 있습니다.API를 제공 할 때, 구성 설정 이름을 다른 PaaS 오퍼링에서 사용되는 다른 이름으로 맵핑 할 수도 있습니다.

이 구성 모듈은 응용 프로그램 코드의 일부일 필요는 없지만 수동으로 대상 시스템의 '/ etc /'하위 디렉토리에 배치 할 수 있습니다. 그런 다음 응용 프로그램이 볼 수 있도록 Python 모듈 검색 경로를 설정해야합니다. 전체 시스템은 WSGI 배포를위한보다 넓은 표준의 일부로 매우 우아하게 만들 수 있지만, 내가 말했듯이 기존 PaaS 제품을 제공 할 때 이러한 표준을 사용하기는 어려울 수 있습니다. .

+0

다른 질문으로 @Graham Dumpleton은 사용하기 위해 설정 파일을 통과하는 깨끗한 방법을 제안합니다 : http://stackoverflow.com/a/25496668/3189 –

22

다른 사람이 Graham의 대답에 좌절하는 경우 여기에 원래 질문에 실제로 적용되는 해결책이 있습니다. 필자는 개인적으로 아파치의 환경 변수를 매우 유용하고 실용적인 것으로 설정했다. 특히 내 자신의 호스팅 환경을 구성하고 원하는대로 할 수 있기 때문이다. (장고 1.5.4에서 테스트)

wsgi.py 작은 노트의

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

, 당신은 현재 WSGIHandler()를 반환 django.core.wsgi.get_wsgi_application의 미래 지향적 방법을 잃게됩니다. WSGIHandler.__call__ 메서드가 업데이트되고 Django도 업데이트하는 경우 인수가 변경되면 WSGIEnvironment 클래스를 업데이트해야 할 수 있습니다. 나는 이것을 편의상 지불하는 아주 작은 페널티라고 생각한다.

+0

django 1.6.5로 테스트하고 작업 중 ... – jliendo

+1

Django 1.8 get_wsgi_application()에는 추가 라인이 있습니다 :'import django','django.setup()','return WSGIHandler()' – Izkata

+1

@Izkata는 여러분이 업데이트 된 방법으로 일을 처리 할 수 ​​있습니까? – ButtersB

4

get_wsgi_application과 같은 미래의 대안이 있습니다. 또한 장고 초기화에서 사용할 환경 변수를 설정할 수 있습니다. mod_wsgi이 프로세스를 관리하는 방법

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

나는 100 % 분명 아니지만, 나는 그것이 매우 자주 WSGI 응용 프로그램을 다시로드하지 않습니다 가정합니다. 그렇다면 Django 초기화로 인한 성능 저하는 첫 번째 요청에서 한 번만 발생합니다. 당신이 장고를 초기화하기 전에 환경 변수를 설정할 필요가없는 경우

또는, 당신은 사용하여 다음을 수행 할 수 있습니다

장고 1.11를 들어
# 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) 
+0

작동하지만, 놓친 것 :''os.environ.setdefault ("DJANGO_SETTINGS_MODULE", "project.settings")'' – NBajanca

+0

당신의 솔루션은 Django 1.10에서도 작동합니다 – ozw1z5rd

0

:

아파치 설정 :

<VirtualHost *:80 > 
    ... 
    SetEnv VAR_NAME VAR_VALUE 
</VirtualHost> 

wsgi.py :

import os 
import django 
from django.core.handlers.wsgi import WSGIHandler 

class WSGIEnvironment(WSGIHandler): 
    def __call__(self, environ, start_response): 
     os.environ["VAR_NAME"] = environ.get("VAR_NAME", "") 
     return super(WSGIEnvironment, self).__call__(environ, start_response) 

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") 
django.setup(set_prefix=False) 
application = WSGIEnvironment() 
관련 문제