Как управлять локальными и производственными настройками в Django?

298

Каков рекомендуемый способ обработки настроек для локальной разработки и производственного сервера? Некоторые из них (например, константы и т. Д.) Могут быть изменены / доступны в обоих, но некоторые из них (например, пути к статическим файлам) должны оставаться разными и, следовательно, не должны перезаписываться при каждом развертывании нового кода.

В настоящее время я добавляю все константы в settings.py. Но каждый раз, когда я изменяю некоторую константу локально, мне приходится копировать ее на рабочий сервер и редактировать файл для конкретных производственных изменений ... :(

Изменить: похоже, что нет стандартного ответа на этот вопрос, я принял самый популярный метод.

АКВ
источник
3
См. Stackoverflow.com/questions/88259/…
Марк Лавин
Пожалуйста, посмотрите на django-конфигурации .
JJD
2
Принятый метод больше не является самым популярным.
Даниэль
2
django-split-settings очень прост в использовании. Не требует перезаписи каких-либо настроек по умолчанию.
Соболевн
Вам следует использовать файл base.py и в вашем local.py «из .base import *», то же самое в вашем production.py «из .base import *», вам нужно запустить ваш проект с помощью: python manage.py runserver - settings = имя_проекта.settings.local
Роберт Солис

Ответы:

127

В settings.py:

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

Вы можете переопределить то, что нужно в local_settings.py; тогда он должен оставаться вне вашего контроля версий. Но так как вы упоминаете о копировании, я думаю, вы не используете ни один;)

ohnoes
источник
3
Чтобы упростить отслеживание / развертывание новых настроек, используйте «local_settings.py» на компьютерах для производства / тестирования и ни одного на стадии разработки.
Джон Ми
8
Я так и делаю - добавляю эти строки в конец
файла
61
Этот подход означает, что у вас есть неверсированный код, работающий в процессе разработки и производства. И у каждого разработчика своя кодовая база. Я называю здесь анти-паттерн.
пиданный
8
@pydanny Проблема в том, что Django хранит свою конфигурацию в файле .py. Вы не можете ожидать, что все разработчики и производственный сервер будут использовать одинаковые настройки, поэтому вам нужно изменить этот файл .py или реализовать какое-либо альтернативное решение (файлы .ini, окружение и т. Д.).
Tupteq
3
Я предпочитаю вызывать модуль, settings_localа не local_settingsгруппировать его settings.pyв алфавитных списках папок. Хранить settings_local.pyвне контроля версий, используя .gitignoreкак учетные данные, не принадлежащие Git. Представьте себе открытый источник их случайно. Я держу в Git файл шаблона, который называется settings_local.py.txtвместо.
Фмалина
297

Two Scoops of Django: Best Practices для 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.

gene_wood
источник
62
Обратите внимание, что вместо использования --settingsкаждый раз, вы можете установить DJANGO_SETTINGS_MODULEenvvar. Это хорошо работает, например, с Heroku: установите его глобально на производство, затем переопределите его с помощью dev в вашем файле .env.
Саймон Вебер
9
DJANGO_SETTINGS_MODULEСпасибо, Саймон, лучше всего использовать env var.
Кибибу
20
Возможно, вам придется изменить BASE_DIRнастройки наos.path.dirname(os.path.realpath(os.path.dirname(__file__) + "/.."))
Петр Пеллер
5
@rsp в соответствии с django docs, вы импортируете from django.conf import settingsэто объект, который абстрагирует интерфейс и отсоединяет код от расположения настроек, docs.djangoproject.com/en/dev/topics/settings/…
3
Если я установлю DJANGO_SETTINGS_MODULE через переменную окружения, мне все равно понадобится os.environ.setdefault ("DJANGO_SETTINGS_MODULE", "projectname.settings.production") в моем файле wsgi.py? Кроме того, я установил переменную среды с помощью: export DJANGO_SETTINGS_MODULE = projectname.settings.local, но затем он теряется при закрытии терминала. Что я могу сделать, чтобы сохранить его? Должен ли я добавить эту строку в файл bashrc?
Kritz
71

Вместо этого 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.pyin prod.pyили dev.py, и вы можете переопределить все из __init__.py.
  5. Это простой питон. Нет повторного импорта хаков.
MiniQuark
источник
2
Я все еще пытаюсь выяснить, что установить в моих файлах project.wsgi и manage.py для файла настроек. Вы пролите свет на это? В частности, в моем файле manage.py у меня есть os.environ.setdefault("DJANGO_SETTINGS_MODULE", "foobar.settings")foobar - папка с __init__.pyфайлом, а настройки - это папка с __init__.pyфайлом, содержащим мои секреты и импортирующим dev.py, который затем импортирует common.py. Редактировать Nevermind, у меня не было установлен модуль, который был необходим. Виноват! Это прекрасно работает !!
января
5
Две вещи: 1) лучше установить Debug = True в вашем dev.py, а не = False в вашем prod.py. 2) Вместо того, чтобы переключаться в init .py, переключайтесь с помощью среды DJANGO_SETTINGS_MODULE var. Это поможет с развертыванием PAAS (например, Heroku).
Роб Грант
Когда я использую эту настройку в django 1.8.4 и пытаюсь запустить сервер запуска, я получаю «django.core.exceptions.ImproperlyConfigured: параметр SECRET_KEY не должен быть пустым.», Даже если у меня есть SECRET_KEY в моем файле init .py. Я что-то упускаю?
polarcare
не является ли использование чего-то вроде AWS_SECRET_ACCESS_KEY = os.getenv ("AWS_SECRET_ACCESS_KEY") более безопасным? Честный вопрос - я знаю, почему вы не хотите, чтобы он был версионным, но другой альтернативой является получение его из среды. Конечно, возникает вопрос об установке переменной среды, но это может быть оставлено на усмотрение вашего механизма развертывания, нет?
JL Peyret
20

Я использую слегка модифицированную версию стиля настроек «если отладка», которую опубликовал Харпер Шелби. Очевидно, что в зависимости от среды (win / linux / и т. Д.) Код может быть немного подправлен.

Раньше я использовал «if 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).

Т. Стоун
источник
Это та вещь, которую настройки Django, являющиеся фактическим файлом кода, позволяют, и я намекал на это. Я не делал ничего подобного сам, но это определенно решение, которое может быть лучшим ответом, чем мой.
Харпер Шелби
3
Я просто столкнулся с этим в первый раз и решил (успешно!) Использовать ваше решение, с небольшой разницей: я использовал uuid.getnode (), чтобы найти uuid моей системы. Поэтому я тестирую, если uuid.getnode () == 12345678901 (на самом деле другое число) вместо теста os.environ, который вы использовали. Я не смог найти документацию, которая бы убедила меня, что os.environ ['COMPUTERNAME'] уникально для каждого компьютера.
Джо Голтон
os.environ ['COMPUTERNAME'] не работает в Amazon AWS Ubuntu. Я получаю KeyError.
Ню Эверест
При использовании UUID это решение оказалось лучшим и самым простым для меня. Это не требует много сложных и чрезмерно модульных пэчворка. В производственной среде вам все еще нужно поместить пароли базы данных и SECRET_KEY в отдельный файл, который находится вне контроля версий.
Ню Эверест
os.environ['COMPUTERNAME']к сожалению не работает на PythonAnywhere. Вы получаете KeyError.
nbeuchat
14

Я использую settings_local.py и settings_production.py. Попробовав несколько вариантов, я обнаружил, что со сложными решениями легко тратить время, когда два файла настроек кажутся легкими и быстрыми.

Когда вы используете mod_python / mod_wsgi для вашего проекта Django, вам нужно указать его в файле настроек. Если вы укажете на app / settings_local.py на локальном сервере и app / settings_production.py на рабочем сервере, жизнь станет проще. Просто отредактируйте соответствующий файл настроек и перезапустите сервер (сервер разработки Django перезапустится автоматически).

Кай
источник
2
А как насчет локального сервера разработки? Есть ли способ сообщить серверу django (запустить с помощью python manage.py runserver), какой файл настроек использовать?
А
2
@akv, если вы добавите --settings = [имя модуля] (без расширения .py) в конец команды runserver, вы можете указать, какой файл настроек использовать. Если вы собираетесь это сделать, сделайте себе одолжение и создайте сценарий оболочки / пакетный файл с настроенными параметрами разработки. Поверьте мне, ваши пальцы будут вам благодарны.
Т. Стоун
это решение, которое я использую. взламывать файл настроек, который будет использоваться как для производства, так и для разработки, грязно
Джордж Годик
4
Я думаю, что лучше использовать settings.py в разработке, так как вам не нужно указывать это все время.
Андре Боссард
Правильно ли я считаю, что этот метод требует импорта модуля настроек через прокси-сервер django.conf.settings? В противном случае вам нужно будет отредактировать декларации импорта, чтобы они указывали на правильный файл настроек при запуске.
Groady
8

TL; DR: хитрость заключается в том, чтобы изменить os.environmentперед импортом settings/base.pyв любой settings/<purpose>.py, это значительно упростит вещи.


Просто думать обо всех этих переплетающихся файлах вызывает у меня головную боль. Объединение, импорт (иногда условно), переопределение, исправление того, что уже было установлено в случаеDEBUG настройки изменились позже. Какой кошмар!

Через годы я прошел через все различные решения. Все они несколько работают, но так больно управлять. WTF! Нам действительно нужны все эти хлопоты? Мы начали с одногоsettings.py файла. Теперь нам нужна документация только для того, чтобы правильно объединить все это в правильном порядке!

Я надеюсь, что я наконец достиг (моего) сладкого места с решением ниже.

Давайте вспомним цели (некоторые общие, некоторые мои)

  1. Храните секреты в секрете - не храните их в репо!

  2. Установить / прочитать ключи и секреты через настройки среды, 12-факторный стиль .

  3. Имеют разумные запасные значения по умолчанию. В идеале для местного развития вам не нужно ничего больше, чем по умолчанию.

  4. … Но старайтесь сохранить производство по умолчанию. Лучше пропустить переопределение настроек локально, чем не забывать корректировать настройки по умолчанию, безопасные для производства.

  5. Иметь возможность включать DEBUG/ выключать таким образом, чтобы это могло повлиять на другие настройки (например, использовать сжатый JavaScript или нет).

  6. Переключение между целевыми настройками, такими как локальные / тестирование / постановка / производство, должно основываться только на DJANGO_SETTINGS_MODULE, и не более того.

  7. … Но разрешить дальнейшую параметризацию через настройки среды, такие как DATABASE_URL.

  8. … Также позволяют им использовать различные настройки назначения и запускать их локально рядом, например. настройка производства на локальном компьютере разработчика для доступа к производственной базе данных или сжатым таблицам стилей для дымовых испытаний.

  9. Ошибка, если переменная окружения не установлена ​​явно (требуется как минимум пустое значение), особенно в производстве, например. EMAIL_HOST_PASSWORD,

  10. Отвечать на настройки по умолчанию DJANGO_SETTINGS_MODULEв manage.py во время запуска проекта django-admin

  11. Держите условные к минимуму, если условие определили тип среды (например, для лога - файла производство набора и этого вращения), настройки переопределения соответствующего файла замыслили настройки.

Не

  1. Не позволяйте django читать настройки DJANGO_SETTINGS_MODULE из файла.
    Тьфу! Подумайте, как это мета. Если вам нужен файл (например, docker env), прочитайте его в среду перед запуском процесса django.

  2. Не переопределяйте DJANGO_SETTINGS_MODULE в коде вашего проекта / приложения, например. основанный на имени хоста или имени процесса.
    Если вам лень устанавливать переменные окружения (например, for setup.py test), сделайте это в инструментах непосредственно перед запуском кода проекта.

  3. Избегайте магии и исправлений того, как django читает свои настройки, предварительно обрабатывайте настройки, но не вмешивайтесь впоследствии.

  4. Никакой сложной логики, основанной на глупости. Конфигурация должна быть фиксированной и материализованной, а не вычисленной на лету. Предоставление запасных значений по умолчанию - достаточно логики.
    Вы действительно хотите отладить, почему локально у вас есть правильный набор настроек, но при работе на удаленном сервере, на одной из ста машин что-то вычисляется по-другому? Ой! Модульные тесты? Для настроек? Шутки в сторону?

Решение

Моя стратегия состоит из превосходной django-environment, используемой с iniфайлами стилей, обеспечивающей os.environmentнастройки по умолчанию для локальной разработки, некоторые минимальные и короткие settings/<purpose>.pyфайлы, которые имеют import settings/base.py ПОСЛЕ того, как os.environmentбыло установлено изINI файла. Это эффективно дает нам инъекцию настроек.

Хитрость заключается в том, чтобы изменить os.environmentперед импортомsettings/base.py .

Чтобы увидеть полный пример, сделайте репо: 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 на сбой на любом другом компьютере, если он отсутствует в среде.

Настройки / 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

Настройки / production.py

Для производства нам не следует ожидать файл среды, но его легче получить, если мы что-то тестируем. Но в любом случае, чтобы не обеспечить несколько встроенных значений по умолчанию, так что settings/base.pyможете реагировать соответственно.

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

Основными интересными моментами здесь являются DEBUGи ASSETS_DEBUGпереопределения, они будут применены к питонуos.environ ТОЛЬКО, если они ПРОПУСКАЮТСЯ от среды и файла.

Это будут наши производственные настройки по умолчанию, нет необходимости помещать их в среду или файл, но они могут быть переопределены при необходимости. Ухоженная!

Настройки / base.py

Это ваши в основном настройки ванильного django, с несколькими условными выражениями и множеством чтений из среды. Здесь есть почти все, поддерживая согласованное и максимально похожее окружение.

Основные различия приведены ниже (я надеюсь, что они говорят сами за себя):

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 - локальные настройки по умолчанию для легкого запуска
Януш Сконечны
источник
Привет, Януш ... так в файле .env будут все ключи API, ключи аутентификации, пароли и т. Д.? Так же, как TWILLIO_API = "abc123"? Или TWILLIO_API = env ("TWILLIO_API")?
dbinott
Да, но это только запасной вариант для параметров среды. Этот файл удобен для разработки, но не сохраняется в репозитории и не передается в производство, где вы должны строго использовать параметры среды или эквивалент вашей платформы, который, в свою очередь, задает параметры среды для процесса сервера.
Януш Сконечны
7

Я управляю своими конфигурациями с помощью django-split-settings .

Это замена для настроек по умолчанию. Это простой, но настраиваемый. И рефакторинг ваших существующих настроек не требуется.

Вот небольшой пример (файл 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()
    )

Вот и все.

Обновить

Я написал сообщение в блоге об управлении djangoнастройками с django-split-sttings. Посмотри!

sobolevn
источник
1
Я попытался это ... наткнулся на стену, как только я попытался запустить свои модульные тесты django ... я просто не мог понять, как указать, какой файл настроек читать
abbood
Я создал для вас суть: gist.github.com/sobolevn/006c734f0520439a4b6c16891d65406c
соболевн
я получил что-то вроде этого в своем коде, поэтому я проверяю настройки. Флаг отладки, чтобы узнать, хочу ли я импортировать вещи ... этот флаг всегда установлен в false в модульных тестах django (см. здесь ), поэтому моя работа заключается в том, чтобы переопределить их в каждый тест, как это так
abbood
Но вот еще один вопрос: у моего uwsgi.iniфайла разные настройки в dev / prod. Есть идеи, как заставить его выбирать значения из моего файла настроек?
Abbood
извините, я не понимаю настройку Вы можете задать отдельный вопрос с более подробной информацией, и я постараюсь вам помочь.
Соболевн
6

Проблема с большинством из этих решений заключается в том, что ваши локальные настройки применяются либо до общих, либо после них.

Так что невозможно переопределить такие вещи, как

  • специфичные для env настройки определяют адреса для пула memcached, а в основном файле настроек это значение используется для настройки серверной части кэша
  • специфичные для env настройки добавляют или удаляют приложения / промежуточное ПО по умолчанию

в то же время.

Одно решение может быть реализовано с использованием конфигурационных файлов в стиле "ini" с классом ConfigParser. Он поддерживает несколько файлов, ленивую интерполяцию строк, значения по умолчанию и много других полезностей. После загрузки нескольких файлов можно загружать больше файлов, и их значения будут заменять предыдущие, если они есть.

Вы загружаете один или несколько файлов конфигурации в зависимости от адреса компьютера, переменных среды и даже значений в ранее загруженных файлах конфигурации. Затем вы просто используете проанализированные значения, чтобы заполнить настройки.

Я успешно использовал одну стратегию:

  • Загрузить defaults.iniфайл по умолчанию
  • Проверьте имя машины и загрузите все файлы, которые соответствуют полностью измененному FQDN, от самого короткого соответствия до самого длинного соответствия (поэтому я загрузил net.ini, а net.domain.iniзатем net.domain.webserver01.iniкаждый из них, возможно, переопределяя значения предыдущего). Эта учетная запись также предназначена для машин разработчиков, поэтому каждый из них может настроить предпочитаемый драйвер базы данных и т. Д. Для локальной разработки.
  • Проверьте, объявлено ли «имя кластера», и в этом случае загрузите cluster.cluster_name.ini, что может определять такие вещи, как IP-адреса базы данных и кэша

В качестве примера того, чего вы можете достичь с помощью этого, вы можете определить значение «subdomain» для per-env, которое затем используется в настройках по умолчанию (как hostname: %(subdomain).whatever.net ) для определения всех необходимых имен хостов и файлов cookie, необходимых для работы django.

Это как СУХОЙ, что я мог получить, большинство (существующих) файлов имели только 3 или 4 настройки. Кроме того, мне пришлось управлять конфигурацией клиента, поэтому существовал дополнительный набор файлов конфигурации (с такими вещами, как имена баз данных, пользователи и пароли, назначенный поддомен и т. Д.), По одному или более для каждого клиента.

Можно масштабировать это значение настолько низко или настолько высоко, как необходимо, вы просто помещаете в файл конфигурации ключи, которые вы хотите настроить для каждой среды, и как только требуется новая конфигурация, поместите предыдущее значение в конфигурацию по умолчанию и переопределите его. где необходимо.

Эта система доказала свою надежность и хорошо работает с контролем версий. Он долгое время использовался для управления двумя отдельными кластерами приложений (15 или более отдельных экземпляров сайта django на машину) с более чем 50 клиентами, где кластеры меняли размер и участников в зависимости от настроения системного администратора. ,

переписан
источник
1
У вас есть пример того, как вы загружаете настройки из ini в настройки Django?
Калейссин
См. Docs.python.org/2/library/configparser.html . Вы можете загрузить парсер, config = ConfigParser.ConfigParser() затем прочитать ваши файлы config.read(array_of_filenames)и получить значения, используя config.get(section, option). Итак, сначала вы загружаете свою конфигурацию, а затем используете ее для чтения значений для настроек.
переписано
5

Я также работаю с Laravel, и мне нравится реализация там. Я попытался имитировать это и комбинировать это с решением, предложенным Т. Стоуном (см. Выше):

PRODUCTION_SERVERS = ['*.webfaction.com','*.whatever.com',]

def check_env():
    for item in PRODUCTION_SERVERS:
        match = re.match(r"(^." + item + "$)", socket.gethostname())
        if match:
            return True

if check_env():
    PRODUCTION = True
else:
    PRODUCTION = False

DEBUG = not PRODUCTION

Может быть, что-то подобное поможет вам.

Роберт Кузьма
источник
4

Помните, что settings.py - это файл с живым кодом. Предполагая, что у вас нет DEBUG, установленного на производстве (что является наилучшей практикой), вы можете сделать что-то вроде:

if DEBUG:
    STATIC_PATH = /path/to/dev/files
else:
    STATIC_PATH = /path/to/production/files

Довольно простой, но теоретически вы можете подняться на любой уровень сложности, основываясь только на значении DEBUG - или любой другой переменной или проверке кода, которую вы хотите использовать.

Харпер Шелби
источник
4

Для большинства моих проектов я использую следующую схему:

  1. Создайте settings_base.py, где я храню настройки, общие для всех сред
  2. Всякий раз, когда мне нужно использовать новую среду с особыми требованиями, я создаю новый файл настроек (например, settings_local.py), который наследует содержимое settings_base.py и переопределяет / добавляет надлежащие переменные настроек ( from settings_base import *)

(Для запуска manage.py с пользовательскими настройками файла , который вы просто использовать --settings вариант команды: manage.py <command> --settings=settings_you_wish_to_use.py)

dzida
источник
3

Мое решение этой проблемы также представляет собой сочетание некоторых решений, уже заявленных здесь:

  • Я держу файл с именем, local_settings.pyкоторый имеет содержимое USING_LOCAL = Trueв Dev и USING_LOCAL = FalseProd
  • В settings.pyI сделать импорт в этот файл , чтобы получить USING_LOCALнастройки

Затем я основываю все свои зависящие от среды настройки на этом:

DEBUG = USING_LOCAL
if USING_LOCAL:
    # dev database settings
else:
    # prod database settings

Я предпочитаю, чтобы у меня было два отдельных файла settings.py, которые мне нужно поддерживать, так как мои настройки проще хранить в одном файле, чем распределять их по нескольким файлам. Например, когда я обновляю настройки, я не забываю сделать это для обеих сред.

Конечно, у каждого метода есть свои недостатки, и этот не исключение. Проблема в том, что я не могу перезаписать local_settings.pyфайл всякий раз, когда отправляю свои изменения в производственную среду, то есть я не могу просто копировать все файлы вслепую, но я могу жить с этим.

Мигель Вентура
источник
3

Я использую разновидность jpartogi, упомянутую выше, которую я нахожу немного короче:

import platform
from django.core.management import execute_manager 

computername = platform.node()

try:
  settings = __import__(computername + '_settings')
except ImportError: 
  import sys
  sys.stderr.write("Error: Can't find the file '%r_settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file local_settings.py does indeed exist, it's causing an ImportError somehow.)\n" % (computername, __file__))
  sys.exit(1)

if __name__ == "__main__":
  execute_manager(settings)

В основном на каждом компьютере (разработка или производство) у меня есть соответствующий файл hostname_settings.py, который загружается динамически.

stratosgear
источник
3

Также есть Django Classy Settings. Я лично большой поклонник этого. Он построен одним из самых активных людей в IRC Django. Вы должны использовать переменные окружения, чтобы установить вещи.

http://django-classy-settings.readthedocs.io/en/latest/

SudoKid
источник
3

1 - Создайте новую папку внутри вашего приложения и присвойте ей настройки.

2 - Теперь создайте в нем новый __init__.pyфайл и внутри него напишите

from .base import *

try:
    from .local import *
except:
    pass

try:
    from .production import *
except:
    pass

3 - Создайте три новых файла в имени папки настроек local.pyи production.pyи base.py.

4 - Внутри base.pyскопируйте весь контент из предыдущей settings.pyпапки и переименуйте его, скажем так old_settings.py.

5 - В base.py измените путь BASE_DIR, чтобы он указывал на новый путь настройки

Старый путь-> BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Новый путь -> BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Таким образом, каталог проекта может быть структурирован и может быть управляемым в рамках производства и местного развития.

Джек Райан
источник
2

Чтобы использовать разные settingsконфигурации в разных средах, создайте другой файл настроек. И в вашем сценарии развертывания, запустите сервер, используя --settings=<my-settings.py>параметр, с помощью которого вы можете использовать различные настройки в разных средах.

Преимущества использования этого подхода :

  1. Ваши настройки будут модульными в зависимости от каждой среды

  2. Вы можете импортировать master_settings.pyсодержащую базовую конфигурацию в environmnet_configuration.pyи переопределить значения, которые вы хотите изменить в этой среде.

  3. Если у вас огромная команда, у каждого разработчика может быть свой собственный ресурс, local_settings.pyкоторый они могут добавить в репозиторий кода без какого-либо риска изменения конфигурации сервера. Вы можете добавить эти локальные настройки, .gitnoreесли вы используете git или .hginoreесли вы Mercurial для контроля версий (или любой другой). Таким образом, локальные настройки даже не будут частью реальной базы кода, сохраняя ее в чистоте.

Мойнуддин Квадри
источник
2

У меня были настройки разделены следующим образом

settings/
     |
     |- base.py
     |- dev.py
     |- prod.py  

У нас есть 3 среды

  • DEV
  • инсценировка
  • производство

Теперь очевидно, что постановка и производство должны иметь максимально возможную схожую среду. Итак, мы сохранилиprod.py для обоих.

Но был случай, когда мне пришлось идентифицировать работающий сервер - это рабочий сервер. @T. Ответ Стоуна помог мне написать чек следующим образом.

from socket import gethostname, gethostbyname  
PROD_HOSTS = ["webserver1", "webserver2"]

DEBUG = False
ALLOWED_HOSTS = [gethostname(), gethostbyname(gethostname()),]


if any(host in PROD_HOSTS for host in ALLOWED_HOSTS):
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True  
Кишор Павар
источник
1

Я разграничил его в manage.py и создал два отдельных файла настроек: local_settings.py и prod_settings.py.

В manage.py я проверяю, является ли сервер локальным или рабочим сервером. Если это локальный сервер, он загружает local_settings.py, а это рабочий сервер, он загружает prod_settings.py. В основном это выглядит так:

#!/usr/bin/env python
import sys
import socket
from django.core.management import execute_manager 

ipaddress = socket.gethostbyname( socket.gethostname() )
if ipaddress == '127.0.0.1':
    try:
        import local_settings # Assumed to be in the same directory.
        settings = local_settings
    except ImportError:
        import sys
        sys.stderr.write("Error: Can't find the file 'local_settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file local_settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
        sys.exit(1)
else:
    try:
        import prod_settings # Assumed to be in the same directory.
        settings = prod_settings    
    except ImportError:
        import sys
        sys.stderr.write("Error: Can't find the file 'prod_settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file prod_settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
        sys.exit(1)

if __name__ == "__main__":
    execute_manager(settings)

Я обнаружил, что проще разделить файл настроек на два отдельных файла, вместо того, чтобы выполнять множество операций if в файле настроек.

Джошуа Партоги
источник
1

В качестве альтернативы для поддержки другого файла, если вы: Если вы используете git или любую другую VCS для передачи кодов с локального на сервер, вы можете просто добавить файл настроек в .gitignore.

Это позволит вам иметь разный контент в обоих местах без каких-либо проблем. Таким образом, на сервере вы можете настроить независимую версию settings.py, и любые изменения, сделанные на локальном компьютере, не будут отражаться на сервере и наоборот.

Кроме того, он удалит файл settings.py из github, что является большой ошибкой, которую, как я видел, делают многие новички.

sprksh
источник
0

Я думаю, что лучшее решение предлагает @T. Стоун, но я не знаю, почему просто не использовать флаг DEBUG в Django. Я пишу код ниже для моего сайта:

if DEBUG:
    from .local_settings import *

Простые решения всегда лучше сложных.

seyedrezafar
источник
-2

Я нашел ответы здесь очень полезными. (Было ли это решено более окончательно? Последний ответ был год назад.) После рассмотрения всех перечисленных подходов я нашел решение, которого здесь не увидел.

Мои критерии были:

  • Все должно быть в системе контроля версий. Я не люблю неряшливые кусочки, валяющиеся вокруг.
  • В идеале, хранить настройки в одном файле. Я забываю вещи, если я не смотрю прямо на них :)
  • Нет ручного редактирования для развертывания. Должен быть в состоянии проверить / подтолкнуть / развернуть с помощью одной команды фабрики.
  • Избегайте утечки настроек разработки в производство.
  • Держите как можно ближе к «стандартной» (* кашель *) раскладке Django, насколько это возможно.

Я думал, что переключение на хост-машину имело некоторый смысл, но потом понял, что реальная проблема заключается в разных настройках для разных сред , и у меня был момент ага. Я поместил этот код в конец моего файла settings.py:

try:
    os.environ['DJANGO_DEVELOPMENT_SERVER'] # throws error if unset
    DEBUG = True
    TEMPLATE_DEBUG = True
    # This is naive but possible. Could also redeclare full app set to control ordering. 
    # Note that it requires a list rather than the generated tuple.
    INSTALLED_APPS.extend([
        'debug_toolbar',
        'django_nose',
    ])
    # Production database settings, alternate static/media paths, etc...
except KeyError: 
    print 'DJANGO_DEVELOPMENT_SERVER environment var not set; using production settings'

Таким образом, приложение по умолчанию настроено на производственные параметры, что означает, что вы явно «заносите в белый список» свою среду разработки. Гораздо безопаснее забыть установить переменную окружения локально, чем если бы это было наоборот, и вы забыли установить что-то в работе и позволить использовать некоторые параметры разработки.

При локальной разработке, либо из оболочки, либо в файле .bash_profile, либо где угодно:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(Или, если вы разрабатываете для Windows, установите через панель управления или как там ее называют в наши дни ... Windows всегда делала это настолько неясным, что вы могли устанавливать переменные среды.)

При таком подходе все настройки dev находятся в одном (стандартном) месте и при необходимости просто перекрывают производственные. Любое переключение с настройками разработки должно быть абсолютно безопасным, чтобы взять на себя контроль над исходным кодом без ущерба для производства.

Джейсон Бойд
источник
Лучше просто поддерживать разные конфигурационные файлы и выбирать с помощью стандартной переменной env DJango DJANGO_SETTINGS_MODULE
Роб Грант