[python] Django에서 로컬 및 프로덕션 설정을 관리하는 방법은 무엇입니까?

로컬 개발 및 프로덕션 서버의 설정을 처리하는 데 권장되는 방법은 무엇입니까? 상수 등의 일부는 변경하거나 액세스 할 수 있지만 정적 파일 경로와 같은 일부는 다르게 유지해야하므로 새 코드가 배포 될 때마다 덮어 쓰지 않아야합니다.

현재 모든 상수를 추가하고 있습니다. settings.py 있습니다. 그러나 로컬에서 일부 상수를 변경할 때마다 프로덕션 서버에 복사하고 프로덕션 특정 변경 사항을 위해 파일을 편집해야합니다 … 🙁

편집 :이 질문에 대한 표준 답변이없는 것 같습니다. 가장 인기있는 방법을 수락했습니다.



답변

에서 settings.py:

try:
    from local_settings import *
except ImportError as e:
    pass

필요한 것을 무시할 수 있습니다 local_settings.py. 그런 다음 버전 관리를 벗어나야합니다. 그러나 복사에 대해 언급 했으므로 아무것도 사용하지 않는 것 같습니다.)


답변

Django의 두 가지 특종 : Django 1.5 모범 사례에서는 설정 파일에 버전 제어를 사용하고 파일을 별도의 디렉토리에 저장하는 것이 좋습니다.

project/
    app1/
    app2/
    project/
        __init__.py
        settings/
            __init__.py
            base.py
            local.py
            production.py
    manage.py

base.py동안 파일 (예 : MEDIA_ROOT 또는 ADMIN 등) 일반적인 설정을 포함 local.py하고 production.py사이트 별 설정이 있습니다 :

기본 파일에서 settings/base.py:

INSTALLED_APPS = (
    # common apps...
)

로컬 개발 설정 파일에서 settings/local.py:

from project.settings.base import *

DEBUG = True
INSTALLED_APPS += (
    'debug_toolbar', # and other apps for local development
)

파일 제작 설정 파일에서 settings/production.py:

from project.settings.base import *

DEBUG = False
INSTALLED_APPS += (
    # other apps for production site
)

그런 다음 django를 실행할 때 --settings옵션 을 추가하십시오 .

# Running django for local development
$ ./manage.py runserver 0:8000 --settings=project.settings.local

# Running django shell on the production site
$ ./manage.py shell --settings=project.settings.production

이 책의 저자 는 샘플 프로젝트 레이아웃 템플릿도 작성했습니다. Github에 을 .


답변

대신 settings.py이 레이아웃을 사용하십시오.

.
└── settings/
    ├── __init__.py  <= not versioned
    ├── common.py
    ├── dev.py
    └── prod.py

common.py 대부분의 구성이있는 곳입니다.

prod.py 공통의 모든 것을 가져오고 재정의 해야하는 모든 것을 재정의합니다.

from __future__ import absolute_import # optional, but I like it
from .common import *

# Production overrides
DEBUG = False
#...

마찬가지로 dev.py모든 항목을 가져 common.py와서 재정의해야하는 모든 항목을 재정의합니다.

마지막으로 __init__.py로드 할 설정을 결정하는 위치와 비밀을 저장하는 위치도 있습니다 (따라서이 파일의 버전을 지정하지 않아야 함).

from __future__ import absolute_import
from .prod import *  # or .dev if you want dev

##### DJANGO SECRETS
SECRET_KEY = '(3gd6shenud@&57...'
DATABASES['default']['PASSWORD'] = 'f9kGH...'

##### OTHER SECRETS
AWS_SECRET_ACCESS_KEY = "h50fH..."

이 솔루션에서 내가 좋아하는 것은 :

  1. 비밀을 제외한 모든 것이 버전 관리 시스템에 있습니다.
  2. 대부분의 구성은 한 곳에 common.py있습니다.
  3. 생산물에 특정한 것들이 들어가고 prod.py, 실체에 특정한 것들이 들어갑니다 dev.py. 간단 해.
  4. 당신은에서 물건을 무시할 수 있습니다 common.py에서 prod.py또는 dev.py, 당신은 아무것도를 대체 할 수 있습니다__init__.py .
  5. 간단한 파이썬입니다. 다시 가져 오기 해킹이 없습니다.

답변

Harper Shelby가 게시 한 “if DEBUG”스타일 설정의 약간 수정 된 버전을 사용합니다. 분명히 환경 (win / linux / etc.)에 따라 코드를 약간 조정해야 할 수도 있습니다.

과거에는 “DEBUG 인 경우”를 사용했지만 DEUBG를 False로 설정하여 테스트해야하는 경우가 있음을 알게되었습니다. 환경이 생산 또는 개발인지 구분하기를 원했기 때문에 DEBUG 수준을 자유롭게 선택할 수있었습니다.

PRODUCTION_SERVERS = ['WEBSERVER1','WEBSERVER2',]
if os.environ['COMPUTERNAME'] in PRODUCTION_SERVERS:
    PRODUCTION = True
else:
    PRODUCTION = False

DEBUG = not PRODUCTION
TEMPLATE_DEBUG = DEBUG

# ...

if PRODUCTION:
    DATABASE_HOST = '192.168.1.1'
else:
    DATABASE_HOST = 'localhost'

나는 아직도 이런 방법으로 진행중인 작업을 고려하고있다. 모든 기반을 다루는 Django 설정을 처리하는 한 가지 방법을 보지 못했지만 동시에 설정하는 데 번거 로움이 없었습니다 (5x 설정 파일 방법을 사용하지 않았습니다).


답변

settings_local.py와 settings_production.py를 사용합니다. 몇 가지 옵션을 시도한 후 두 개의 설정 파일을 갖는 것이 쉽고 빠르면 복잡한 솔루션으로 시간을 낭비하는 것이 쉽다는 것을 알았습니다.

Django 프로젝트에 mod_python / mod_wsgi를 사용할 때는 설정 파일을 가리켜 야합니다. 로컬 서버의 app / settings_local.py 및 프로덕션 서버의 app / settings_production.py를 가리키면 인생이 쉬워집니다. 적절한 설정 파일을 편집하고 서버를 다시 시작하십시오 (Django 개발 서버가 자동으로 다시 시작됨).


답변

TL; DR : 트릭을 수정하는 것입니다 os.environment당신이 가져 오기 전에 settings/base.py어떤에서 settings/<purpose>.py이 크게 일을 단순화합니다.


이 모든 얽힌 파일에 대해 생각하면 두통이 생깁니다. DEBUG나중에 설정이 변경된 경우에 이미 설정 한 내용의 조합, 가져 오기 (조건에 따라), 재정의, 패치 악몽이야!

몇 년 동안 나는 모든 다른 솔루션을 겪었습니다. 그들은 모두 다소 효과가 있지만 관리하기가 너무 고통 스럽습니다. WTF! 번거 로움이 정말로 필요한가? 하나의 settings.py파일로 시작했습니다 . 이제이 모든 것을 올바른 순서로 올바르게 결합하기위한 문서가 필요합니다!

나는 마침내 아래 해결책으로 (내) 달콤한 자리에 도달하기를 바랍니다.

목표를 되짚어 봅시다 (일부 공통, 일부 내)

  1. 비밀을 비밀로 유지하십시오. 리포지토리에 저장하지 마십시오!

  2. 12 요인 스타일 환경 설정을 통해 키와 비밀을 설정 / 읽습니다 .

  3. 적절한 대체 기본값이 있습니다. 이상적으로는 로컬 개발을 위해 기본값 이외의 다른 것이 필요하지 않습니다.

  4. … 기본 생산을 안전하게 유지하십시오. 프로덕션 환경에서 안전한 기본 설정을 기억해야하는 것보다 로컬에서 설정 재정의를 놓치는 것이 좋습니다.

  5. 전환 할 수있는 기능이 DEBUG다른 설정에 영향을 줄 수있는 방법에 온 / 오프 (예. 압축 된 자바 스크립트를 사용하여 여부를).

  6. 로컬 / 테스트 / 스테이징 / 프로덕션과 같은 목적 설정 간 전환은을 기반으로해야합니다 DJANGO_SETTINGS_MODULE.

  7. …와 같은 환경 설정을 통해 추가 매개 변수화를 허용 DATABASE_URL합니다.

  8. … 또한 서로 다른 목적 설정을 사용하고 로컬로 나란히 실행할 수 있습니다 (예 : 로컬 개발자 시스템의 프로덕션 설정, 프로덕션 데이터베이스에 액세스하거나 연기 테스트 압축 스타일 시트.

  9. 특히 프로덕션 환경에서 환경 변수가 명시 적으로 설정되지 않으면 (최소한 빈 값이 필요함) 실패합니다. EMAIL_HOST_PASSWORD.

  10. django-admin startprojectDJANGO_SETTINGS_MODULE 중 manage.py의 기본 설정에 응답

  11. 조건이있는 경우, 최소한으로 조건문을 유지 목적의 환경 유형 (예를 들면. 생산 세트의 로그 파일과의 회전), 관련 목적의 설정 파일에서 재정의 설정.

하지마

  1. django가 파일에서 DJANGO_SETTINGS_MODULE 설정을 읽지 못하게하십시오.
    어! 이것이 메타인지 생각하십시오. docker env와 같은 파일이 필요한 경우 django 프로세스를 시작하기 전에 환경에서 파일을 읽으십시오.

  2. 프로젝트 / 앱 코드에서 DJANGO_SETTINGS_MODULE을 재정의하지 마십시오 (예 : 호스트 이름 또는 프로세스 이름을 기반으로합니다.
    환경 변수를 설정하는 것이 게으른 경우 (예 :와 같이 setup.py test) 프로젝트 코드를 실행하기 직전에 툴링에서 환경 변수를 설정 하십시오.

  3. django가 설정을 읽는 방법의 마법과 패치를 피하고 설정을 사전 처리하지만 나중에 방해하지는 마십시오.

  4. 복잡한 논리 기반 넌센스가 없습니다. 구성은 즉시 계산되지 않고 수정되고 구체화되어야합니다. 대체 기본값을 제공하는 것만으로도 충분한 논리입니다.
    로컬에서 올바른 설정 세트를 사용하지만 원격 서버, 수백 대의 머신 중 하나에서 다르게 계산 된 이유는 무엇입니까? 오! 단위 테스트? 설정? 진심이야?

해결책

내 전략은 우수한 구성 장고-와 환경 에 사용 ini스타일 파일, 제공 os.environment지역 개발에 대한 기본값을, 최소한의 짧은 settings/<purpose>.py을 가진 파일
import settings/base.py 후에os.environment에서 설정 INI파일. 이것은 효과적으로 일종의 설정 주입을 제공합니다.

여기서 트릭은 os.environment가져 오기 전에 수정하는 것 settings/base.py입니다.

전체 예제를 보려면 repo를 수행하십시오. https://github.com/wooyek/django-settings-strategy

.
   manage.py
├───data
└───website
    ├───settings
          __init__.py   <-- imports local for compatibility
          base.py       <-- almost all the settings, reads from proces environment
          local.py      <-- a few modifications for local development
          production.py <-- ideally is empty and everything is in base
          testing.py    <-- mimics production with a reasonable exeptions
          .env          <-- for local use, not kept in repo
       __init__.py
       urls.py
       wsgi.py

설정 /.env

로컬 개발의 기본값입니다. 주로 필요한 환경 변수를 설정하는 비밀 파일. 로컬 개발에 필요하지 않은 경우 빈 값으로 설정하십시오. 우리는 여기서 기본값을 제공 settings/base.py하며 환경에서 누락 된 경우 다른 시스템에서 실패 하지 않습니다 .

settings / local.py

여기서 발생하는 일은에서 환경을로드 settings/.env한 다음에서 공통 설정을 가져 오는 것입니다 settings/base.py. 그 후 지역 개발을 용이하게하기 위해 몇 가지를 재정의 할 수 있습니다.

import logging
import environ

logging.debug("Settings loading: %s" % __file__)

# This will read missing environment variables from a file
# We wan to do this before loading a base settings as they may depend on environment
environ.Env.read_env(DEBUG='True')

from .base import *

ALLOWED_HOSTS += [
    '127.0.0.1',
    'localhost',
    '.example.com',
    'vagrant',
    ]

# https://docs.djangoproject.com/en/1.6/topics/email/#console-backend
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'

LOGGING['handlers']['mail_admins']['email_backend'] = 'django.core.mail.backends.dummy.EmailBackend'

# Sync task testing
# http://docs.celeryproject.org/en/2.5/configuration.html?highlight=celery_always_eager#celery-always-eager

CELERY_ALWAYS_EAGER = True
CELERY_EAGER_PROPAGATES_EXCEPTIONS = True

settings / production.py

프로덕션 환경에서는 환경 파일을 기 대해서는 안되지만 무언가를 테스트하는 경우 환경 파일이 더 쉽습니다. 그러나 어쨌든 최소한의 인라인 설정을 제공하지 않으므로 settings/base.py그에 따라 응답 할 수 있습니다.

environ.Env.read_env(Path(__file__) / "production.env", DEBUG='False', ASSETS_DEBUG='False')
from .base import *

관심의 주요 포인트는 여기에 있습니다 DEBUGASSETS_DEBUG재 지정, 그들은 파이썬에 적용됩니다 os.environ들이 환경과 파일에서 누락 된 경우에만.

이것들은 프로덕션 기본값이 될 것이며, 환경이나 파일에 넣을 필요는 없지만 필요한 경우 재정의 할 수 있습니다. 산뜻한!

settings / base.py

이것들은 대부분 바닐라 장고 설정이며, 몇 가지 조건부와 환경에서 많은 것을 읽습니다. 거의 모든 것이 여기에 있으며, 모든 목적 환경을 일관되고 유사하게 유지합니다.

주요 차이점은 다음과 같습니다 (자기 설명이 필요합니다).

import environ

# https://github.com/joke2k/django-environ
env = environ.Env()

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# Where BASE_DIR is a django source root, ROOT_DIR is a whole project root
# It may differ BASE_DIR for eg. when your django project code is in `src` folder
# This may help to separate python modules and *django apps* from other stuff
# like documentation, fixtures, docker settings
ROOT_DIR = BASE_DIR

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env('DEBUG', default=False)

INTERNAL_IPS = [
    '127.0.0.1',
]

ALLOWED_HOSTS = []

if 'ALLOWED_HOSTS' in os.environ:
    hosts = os.environ['ALLOWED_HOSTS'].split(" ")
    BASE_URL = "https://" + hosts[0]
    for host in hosts:
        host = host.strip()
        if host:
            ALLOWED_HOSTS.append(host)

SECURE_SSL_REDIRECT = env.bool('SECURE_SSL_REDIRECT', default=False)

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

if "DATABASE_URL" in os.environ:  # pragma: no cover
    # Enable database config through environment
    DATABASES = {
        # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
        'default': env.db(),
    }

    # Make sure we use have all settings we need
    # DATABASES['default']['ENGINE'] = 'django.contrib.gis.db.backends.postgis'
    DATABASES['default']['TEST'] = {'NAME': os.environ.get("DATABASE_TEST_NAME", None)}
    DATABASES['default']['OPTIONS'] = {
        'options': '-c search_path=gis,public,pg_catalog',
        'sslmode': 'require',
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            # 'ENGINE': 'django.contrib.gis.db.backends.spatialite',
            'NAME': os.path.join(ROOT_DIR, 'data', 'db.dev.sqlite3'),
            'TEST': {
                'NAME': os.path.join(ROOT_DIR, 'data', 'db.test.sqlite3'),
            }
        }
    }

STATIC_ROOT = os.path.join(ROOT_DIR, 'static')

# django-assets
# http://django-assets.readthedocs.org/en/latest/settings.html

ASSETS_LOAD_PATH = STATIC_ROOT
ASSETS_ROOT = os.path.join(ROOT_DIR, 'assets', "compressed")
ASSETS_DEBUG = env('ASSETS_DEBUG', default=DEBUG)  # Disable when testing compressed file in DEBUG mode
if ASSETS_DEBUG:
    ASSETS_URL = STATIC_URL
    ASSETS_MANIFEST = "json:{}".format(os.path.join(ASSETS_ROOT, "manifest.json"))
else:
    ASSETS_URL = STATIC_URL + "assets/compressed/"
    ASSETS_MANIFEST = "json:{}".format(os.path.join(STATIC_ROOT, 'assets', "compressed", "manifest.json"))
ASSETS_AUTO_BUILD = ASSETS_DEBUG
ASSETS_MODULES = ('website.assets',)

마지막 비트는 여기에 힘을 보여줍니다. ASSETS_DEBUG합리적인 기본값을 가지고 있으며 settings/production.py, 환경 설정에 의해 재정의 될 수 있고 심지어 재정의 될 수도 있습니다! 예이!

사실상 우리는 중요한 계층 구조를 가지고 있습니다 :

  1. settings / .py-목적에 따라 기본값을 설정하고 비밀을 저장하지 않습니다
  2. settings / base.py-대부분 환경에 의해 제어됩니다
  3. 공정 환경 설정-12 단계 베이비!
  4. settings / .env-쉬운 시작을위한 로컬 기본값

답변

django-split-settings 의 도움으로 구성을 관리합니다 .

기본 설정을 대체합니다. 간단하지만 구성 할 수 있습니다. 기존 설정을 리팩토링 할 필요가 없습니다.

다음은 작은 예입니다 (file example/settings/__init__.py).

from split_settings.tools import optional, include
import os

if os.environ['DJANGO_SETTINGS_MODULE'] == 'example.settings':
    include(
        'components/default.py',
        'components/database.py',
        # This file may be missing:
        optional('local_settings.py'),

        scope=globals()
    )

그게 다야.

최신 정보

의 설정 관리에 대한 블로그 게시물을 작성했습니다 . 보세요!djangodjango-split-sttings