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

236

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

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

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

  • 3
    См. Stackoverflow.com/questions/88259/…
  • 0
    Пожалуйста, посмотрите на django-конфигурации .
Показать ещё 3 комментария
Теги:
deployment

20 ответов

114
Лучший ответ

В settings.py:

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

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

  • 2
    Чтобы упростить отслеживание / развертывание новых настроек, используйте «local_settings.py» на компьютерах для производства / тестирования и ни одного на стадии разработки.
  • 8
    Я так и делаю - добавляю эти строки в конец файла settings.py, чтобы они могли переопределить настройки по умолчанию
Показать ещё 12 комментариев
227

Два сокета 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.

  • 59
    Обратите внимание, что вместо использования --settings каждый раз, вы можете установить DJANGO_SETTINGS_MODULE DJANGO_SETTINGS_MODULE. Это хорошо работает, например, с Heroku: установите его глобально на производство, затем переопределите его с помощью dev в вашем файле .env.
  • 8
    DJANGO_SETTINGS_MODULE использование DJANGO_SETTINGS_MODULE env var - лучшая идея.
Показать ещё 12 комментариев
56

Вместо 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..."

Что мне нравится в этом решении:

  • Все в вашей системе управления версиями, за исключением секретов
  • Большая часть конфигурации находится в одном месте: common.py.
  • Прод-специфические вещи идут в prod.py, dev-specific вещи идут в dev.py. Это просто.
  • Вы можете переопределить материал из common.py в prod.py или dev.py, и вы можете переопределить что-либо в __init__.py.
  • Это простой питон. Нет повторного импорта хаков.
  • 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, у меня не было установлен модуль, который был необходим. Виноват! Это прекрасно работает !!
  • 3
    Две вещи: 1) лучше установить Debug = True в вашем dev.py, а не = False в вашем prod.py. 2) Вместо того, чтобы переключаться в init .py, переключайтесь с использованием среды DJANGO_SETTINGS_MODULE var. Это поможет с развертыванием PAAS (например, Heroku).
Показать ещё 2 комментария
17

Я использую слегка измененную версию настроек стиля "if DEBUG", которую опубликовал Харпер Шелби. Очевидно, что в зависимости от среды (win/linux/etc.), Возможно, потребуется немного изменить код.

Я был в прошлом, используя "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 настроек файлов).

  • 0
    Это та вещь, которую настройки Django, являющиеся фактическим файлом кода, позволяют, и я намекал на это. Я сам ничего подобного не делал, но это определенно решение, которое может быть лучшим ответом, чем мой.
  • 3
    Я просто столкнулся с этим в первый раз и решил (успешно!) Использовать ваше решение, с небольшим отличием: я использовал uuid.getnode (), чтобы найти uuid моей системы. Поэтому я тестирую, если uuid.getnode () == 12345678901 (на самом деле другое число) вместо теста os.environ, который вы использовали. Я не смог найти документацию, которая бы убедила меня, что os.environ ['COMPUTERNAME'] уникально для каждого компьютера.
Показать ещё 4 комментария
14

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

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

  • 2
    А как насчет локального сервера разработки? Есть ли способ сообщить веб- python manage.py runserver django (запустить с помощью python manage.py runserver ), какой файл настроек использовать?
  • 2
    @akv, если вы добавите --settings = [имя модуля] (без расширения .py) в конец команды runserver, вы можете указать, какой файл настроек использовать. Если вы собираетесь это сделать, сделайте себе одолжение и создайте сценарий оболочки / пакетный файл с настроенными параметрами разработки. Поверьте мне, ваши пальцы будут вам благодарны.
Показать ещё 3 комментария
6

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

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

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

Что это.

Update

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

  • 1
    Я попытался это ... наткнулся на стену, как только я попытался запустить свои модульные тесты Django ... я просто не мог понять, как указать, какой файл настроек для чтения из
  • 0
    Я создал для вас суть: gist.github.com/sobolevn/006c734f0520439a4b6c16891d65406c
Показать ещё 4 комментария
6

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

Поэтому невозможно переопределить такие вещи, как

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

в то же время.

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

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

Одна из моих успешных стратегий:

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

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

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

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

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

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

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

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 causing an ImportError somehow.)\n" % (computername, __file__))
  sys.exit(1)

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

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

3

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

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

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

3

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

  • Я сохраняю файл под названием local_settings.py, у которого есть контент USING_LOCAL = True в dev и USING_LOCAL = False в prod
  • В settings.py Я делаю импорт в этот файл, чтобы получить параметр USING_LOCAL

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

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

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

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

2

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

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

1

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

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

    from .base import *

    try:

из .local import *

    except:

передача

     try:

из .production import *

     except:

передача

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

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

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

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

Новый путь → BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(файл)))

теперь таким образом проектный dir может быть структурирован и может управляться между производством и локальным развитием.

1

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


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

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

Надеюсь, я наконец ударил (мое) сладкое пятно с помощью решения ниже.

Обозначьте цели (некоторые общие, некоторые мои)

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

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

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

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

  • У вас есть возможность включать/отключать DEBUG таким образом, который может влиять на другие настройки (например, с помощью сжатого javascript или нет).

  • Переключение между целевыми настройками, такими как local/testing/staging/production, должно основываться только на DJANGO_SETTINGS_MODULE, не более того.

  • ... но разрешить дальнейшую параметризацию с помощью настроек среды, таких как DATABASE_URL.

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

  • Сбой, если переменная среды явно не задана (требуется минимальное значение), особенно в производстве, например. EMAIL_HOST_PASSWORD.

  • Отвечайте по умолчанию DJANGO_SETTINGS_MODULE, установленному в manage.py во время django-admin startproject

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

Не

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

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

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

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

Решение

Моя стратегия состоит из превосходного django-environ, используемого с файлами стиля 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 compatybility
    │   │   base.py       <-- almost all the settings, reads from proces environment 
    │   │   local.py      <-- a few modifications for local development
    │   │   production.py <-- ideally is empy 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 переопределяет, они будут применяться к python 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 и даже тот, который может быть переопределен настройкой среды! Ура!

По сути, мы имеем смешанную иерархию важности:

  • settings/.py - устанавливает значения по умолчанию в зависимости от цели, не хранит секреты
  • settings/base.py - в основном управляется средой
  • настройки среды процесса - 12-ти факторный ребенок!
  • настройки /.env - локальные значения по умолчанию для легкого запуска
  • 0
    Привет, Януш ... так в файл .env будут включены все ключи API, ключи аутентификации, пароли и т. Д.? Так же, как TWILLIO_API = "abc123"? Или TWILLIO_API = env ("TWILLIO_API")?
  • 0
    Да, но это только запасной вариант для параметров среды. Этот файл удобен для разработки, но не сохраняется в репозитории и не передается в производство, где вы должны строго использовать параметры среды или эквивалент вашей платформы, что, в свою очередь, задает параметры среды для процесса сервера.
1

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

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

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

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

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

1

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

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

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

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 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 causing an ImportError somehow.)\n" % __file__)
        sys.exit(1)

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

Мне было проще отделить файл настроек от двух отдельных файлов, вместо того чтобы делать много файлов ifs внутри файла настроек.

0

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

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

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

Мои критерии:

  • Все должно быть в контроле источника. Мне не нравятся болтливые кусочки.
  • В идеале сохраните настройки в одном файле. Я забываю что-то, если я не смотрю прямо на них:)
  • Никаких ручных изменений для развертывания. Должен иметь возможность тестировать/нажимать/развертывать с помощью одной команды ткани.
  • Избегайте утечки настроек разработки в производство.
  • Держитесь как можно ближе к "стандартным" (* cough *) раскладке 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 находятся в одном (стандартном) месте и просто при необходимости заменяют производственные. Любые ошибки, связанные с настройками разработки, должны быть абсолютно безопасными для фиксации контроля источника без какого-либо влияния на производство.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню