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

129

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

Было бы здорово узнать следующее:

  • Как лучше всего справляться с настройками разработки и производства.
  • Как сохранить такие приложения, как django-debug-toolbar, только в среде разработки.
  • Любые другие советы и рекомендации по настройке разработки и развертывания.
Кристиан Робак
источник
Посмотрите здесь: stackoverflow.com/questions/88259/... и здесь code.djangoproject.com/wiki/SplitSettings
алан

Ответы:

109

В DJANGO_SETTINGS_MODULEпеременной среды управления , какой файл настроек Django загрузит.

Поэтому вы создаете отдельные файлы конфигурации для своих соответствующих сред (обратите внимание, что они, конечно, могут быть как import *из отдельного файла «общих настроек»), так и использовать DJANGO_SETTINGS_MODULEдля управления тем, какой из них использовать.

Вот как:

Как отмечено в документации Django:

Значение DJANGO_SETTINGS_MODULE должно быть в синтаксисе пути Python, например mysite.settings. Обратите внимание, что модуль настроек должен находиться на пути поиска импорта Python.

Итак, предположим, что вы создали myapp/production_settings.pyи myapp/test_settings.pyв своем исходном репозитории.

В этом случае вы соответственно настроили DJANGO_SETTINGS_MODULE=myapp.production_settingsбы использовать первое и DJANGO_SETTINGS_MODULE=myapp.test_settingsиспользовать второе.


С этого момента проблема сводится к установке DJANGO_SETTINGS_MODULEпеременной окружения.

Настройка DJANGO_SETTINGS_MODULEс помощью скрипта или оболочки

Затем вы можете использовать сценарий начальной загрузки или диспетчер процессов для загрузки правильных параметров (путем установки среды) или просто запустить его из оболочки перед запуском Django : export DJANGO_SETTINGS_MODULE=myapp.production_settings.

Обратите внимание, что вы можете запустить этот экспорт в любое время из оболочки - он не должен находиться в вашем .bashrcили чем-то еще.

настройка DJANGO_SETTINGS_MODULE с помощью диспетчера процессов

Если вам не нравится писать сценарий начальной загрузки, который устанавливает среду (и есть очень веские причины так думать!), Я бы порекомендовал использовать диспетчер процессов:


Наконец, обратите внимание, что вы можете использовать PYTHONPATHпеременную для хранения настроек в совершенно другом месте (например, на производственном сервере, где они хранятся /etc/). Это позволяет отделить конфигурацию от файлов приложения. Вы можете этого захотеть, а можете и не захотеть, это зависит от структуры вашего приложения.

Томас Ороско
источник
7
Чтобы уточнить, поскольку settings.pyфайл хранится SiteName/settings.pyпо умолчанию, если вы поместите свои альтернативные файлы настроек в тот же каталог, строка, добавленная в bin / activate, должна читать DJANGO_SETTINGS_MODULE="SiteName.test_settings"В противном случае отличный ответ!
Алексбхандари
2
по совпадению вы знаете учебник о том, как делать это шаг за шагом, я новичок в Django и не знаю, где установить DJANGO_SETTINGS_MODULE или PYTHONPATH
Jesus Almaral - Hackaprende
Это решение не подходит для conda env. В conda env нет bin / activate.
Pouya Yousefi
1
@PouyaYousefi: вам абсолютно не нужно использовать virtualenv, чтобы использовать этот ответ. Ответ на самом деле сводится к двум шагам: а) использовать отдельные файлы настроек и б) использовать, DJANGO_SETTINGS_MODULEчтобы выбрать тот, который вы хотите использовать. Модификация bin/activate - это одно, чтобы сделать последнее (TBH, я больше не думаю, что это хорошая идея, поэтому я убрал это), но это не единственный вариант.
Томас Ороско
Это также полезно, если вы используете Django в версии сообщества pycharm и вам нужно правильно запускать модульные тесты как в командной строке, так и в сообществе pycharm. Предположим, вы создали только один простой файл конфигурации в myapp / settings.py в исходном репозитории. В этом случае вы должны установить «DJANGO_SETTINGS_MODULE = myapp.settings» в меню RUN / Edit Configuration / Environment variable, чтобы использовать его в последнем случае для запуска тестовых случаев.
F.Tamy 03
58

По умолчанию используйте производственные настройки, но создайте файл с именем settings_dev.pyв той же папке, что и ваш settings.pyфайл. Добавьте туда переопределения, например DEBUG=True.

На компьютере, который будет использоваться для разработки, добавьте это в свой ~/.bashrcфайл:

export DJANGO_DEVELOPMENT=true

Внизу settings.pyфайла добавьте следующее.

# Override production variables if DJANGO_DEVELOPMENT env variable is set
if os.environ.get('DJANGO_DEVELOPMENT'):
    from settings_dev import *  # or specific overrides

(Обратите внимание, что импорт * в Python обычно следует избегать )

По умолчанию производственные серверы ничего не отменяют. Готово!

По сравнению с другими ответами, этот проще, потому что не требует обновления PYTHONPATHили настройки, DJANGO_SETTINGS_MODULEкоторая позволяет вам работать только над одним проектом django за раз.

CS01
источник
8
как это не правильный ответ? ТАК сейчас действительно беспорядок. Ty cs01
codyc4321
if os.environ.get('DJANGO_DEVELOPMENT', 'true')тоже работает. Я упоминаю об этом только потому, что вышеуказанный is not trueметод не удалось импортировать для меня в Python 3.6.
BRT
1
@brt - это плохая идея: он всегда будет использовать ваши DEVнастройки, что приведет к утечке личных данных на общедоступном сервере. Вы действительно просто хотите проверить, DJANGO_DEVELOPMENTсуществует ли переменная среды (т.е. is not None).
cs01
Спасибо за информацию, @ cs01. Я понял, что сделал что-то не так, когда взорвал свой сайт из-за неправильной загрузки настроек, но я не был уверен, почему settings_dev.pyзагружается на сервер.
BRT
2
@ cs01 Я бы пошел дальше и убедился, что он существует и правдив, просто сняв is not Noneчек. Также os.getenvесть стенография
Tjorriemorrie
35

Обычно у меня есть один файл настроек для каждой среды и общий файл настроек:

/myproject/
  settings.production.py
  settings.development.py
  shared_settings.py

В каждом из моих файлов среды есть:

try:
    from shared_settings import *
except ImportError:
    pass

Это позволяет мне при необходимости переопределить общие настройки (путем добавления изменений под этой строфой).

Затем я выбираю, какие файлы настроек использовать, связывая их с settings.py:

ln -s settings.development.py settings.py
Дэниел Уоткинс
источник
2
Как вы относитесь к запрету pep8 import *? Вы отключите эту проверку? Я завернул этот импорт в exec()файл, но тогда у меня не может быть условий для переменных, которые не определены в этом файле, и я не могу изменять INSTALLED_APPSпеременную, потому что она «не определена»
Михаил
11
Мы не линзуем наши файлы настроек, потому что они на самом деле не столько код, сколько конфигурация, выраженная на Python.
Дэниел Уоткинс,
18

Вот как я это делаю за 6 простых шагов:

  1. Создайте папку в каталоге вашего проекта и назовите ее settings.

    Структура проекта:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
  2. Создайте четыре питона файлы внутри settingsкаталога , а именно __init__.py, base.py, dev.pyиprod.py

    Файлы настроек:

    settings/
         __init__.py
         base.py
         prod.py
         dev.py 
  3. Откройте __init__.pyи заполните его следующим содержимым:

    init .py:

    from .base import *
    # you need to set "myproject = 'prod'" as an environment variable
    # in your OS (on which your website is hosted)
    if os.environ['myproject'] == 'prod':
       from .prod import *
    else:
       from .dev import *
  4. Откройте base.pyи заполните его всеми общими настройками (которые будут использоваться как в производстве, так и в разработке), например:

    base.py:

    import os
    ...
    INSTALLED_APPS = [...]
    MIDDLEWARE = [...]
    TEMPLATES = [{...}]
    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_ROOT = os.path.join(BASE_DIR, '/path/')
    MEDIA_URL = '/path/'
  5. Откройте dev.pyи включите то, что относится к разработке, например:

    dev.py:

    DEBUG = True
    ALLOWED_HOSTS = ['localhost']
    ...
  6. Откройте prod.pyи включите то, что специфично для производства, например:

    prod.py:

    DEBUG = False
    ALLOWED_HOSTS = ['www.example.com']
    LOGGING = [...]
    ...
Ahtisham
источник
10

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

try:
  from settings_dev import *
except ImportError:
  pass

Вы храните отдельные settings_*файлы для каждого этапа.

Вверху settings_dev.pyфайла добавьте это:

import sys
globals().update(vars(sys.modules['settings']))

Чтобы импортировать переменные, которые вам нужно изменить.

В этой вики-статье есть больше идей о том, как разделить ваши настройки.

Бурхан Халид
источник
Спасибо, Burham! При развертывании приложения мне просто нужно удалить файл settings_dev, чтобы увидеть мои настройки развертывания в действии?
Кристиан Робак
Да, или замените импорт наsettings_prod.py
Бурхан Халид
1
Однако редактирование главного файла settings.py при развертывании означает, что он будет конфликтовать с системой управления версиями, поэтому это не обязательно лучший способ продвижения вперед. Я бы сказал, что вариант Томаса Ороско лучший - вы можете установить DJANGO_SETTINGS_MODULE в своем скрипте постактивации virtualenv или в настройках gunicorn или mod_wsgi
Стив Джалим
1
Возможно, следует упомянуть, что вы никогда не добавляете в систему управления версиями файлы для конкретной сцены. Я предположил, что было понятно, что вы не будете распространять настройки, относящиеся к определенной стадии проекта.
Бурхан Халид
Если вы используете virtualenv, обычно по умолчанию используется {{project_name}}. Settings. Таким образом, «настройки» не будут ключевыми в sys.modules. Это будет myproject.settings (или другое название вашего проекта). Вы можете использовать modname = "%s.settings" % ".".join(__name__.split('.')[:-1])для получения полного имени модуля, а затем globals().update(vars(sys.modules[modname])). Я считаю, что для меня это хорошо работает. Конечно, отказ от бита о программном определении имени модуля в пользу строки, вероятно, также сработает в большинстве случаев.
Eric
9

Я использую потрясающие конфигурации django , и все настройки хранятся в моем settings.py:

from configurations import Configuration

class Base(Configuration):
    # all the base settings here...
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    ...

class Develop(Base):
    # development settings here...
    DEBUG = True 
    ...

class Production(Base):
    # production settings here...
    DEBUG = False

Чтобы настроить проект Django, я просто следил за документами .

Риккардо Лешютта
источник
7

Вот используемый нами подход:

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

Учитывая следующую структуру:

...
.env.json           # the file containing all specific credentials and parameters
.gitignore          # the .gitignore file to exclude `.env.json`
project_name/       # project dir (the one which django-admin.py creates)
  accounts/         # project's apps
    __init__.py
    ...
  ...
  env.py            # the file to load credentials
  settings/
    __init__.py     # main settings file
    database.py     # database conf
    storage.py      # storage conf
    ...
venv                # virtualenv
...

С .env.jsonкак:

{
    "debug": false,
    "allowed_hosts": ["mydomain.com"],
    "django_secret_key": "my_very_long_secret_key",
    "db_password": "my_db_password",
    "db_name": "my_db_name",
    "db_user": "my_db_user",
    "db_host": "my_db_host",
}

И project_name/env.py:

<!-- language: lang-python -->
import json
import os


def get_credentials():
    env_file_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    with open(os.path.join(env_file_dir, '.env.json'), 'r') as f:
        creds = json.loads(f.read())
    return creds


credentials = get_credentials()

У нас могут быть следующие настройки:

<!-- language: lang-py -->
# project_name/settings/__init__.py
from project_name.env import credentials
from project_name.settings.database import *
from project_name.settings.storage import *
...

SECRET_KEY = credentials.get('django_secret_key')

DEBUG = credentials.get('debug')

ALLOWED_HOSTS = credentials.get('allowed_hosts', [])

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ...
]

if DEBUG:
    INSTALLED_APPS += ['debug_toolbar']

...

# project_name/settings/database.py
from project_name.env import credentials

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': credentials.get('db_name', ''),
        'USER': credentials.get('db_user', ''),
        'HOST': credentials.get('db_host', ''),
        'PASSWORD': credentials.get('db_password', ''),
        'PORT': '5432',
    }
}

Преимущества этого решения:

  • учетные данные и конфигурации пользователя для локальной разработки без изменения репозитория git;
  • конфигурация для конкретной среды , у вас может быть, например, три разных среды с тремя разными, .env.jsonтакими как dev, stagging и production;
  • учетные данные отсутствуют в репозитории

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

Charlesthk
источник
при условии , где envэто заменить dev, и prodт.д.? Что находится в старом settings.pyфайле? Что в storage.pyи database.py?
dbinott
Привет, @dbinott, вы можете легко обновить env.pyфайл, чтобы вы могли выбирать, с помощью переменной среды, какой файл загружать
Charlesthk
Например: conf = os.environ.get ('CONF', '') file_ = f ".env. {Conf} .json"
Charlesthk
Почему вам нужен json, а не собственный тип данных python?
авиаудар
4

Я использую следующую файловую структуру:

project/
   ...
   settings/
   settings/common.py
   settings/local.py
   settings/prod.py
   settings/__init__.py -> local.py

Так __init__.pyчто это ссылка (ln в unix или mklink в Windows) на local.pyили может быть prod.pyтак, чтобы конфигурация все еще в project.settingsмодуле была чистой и организованной, и если вы хотите использовать конкретную конфигурацию, вы можете использовать переменную среды DJANGO_SETTINGS_MODULEдляproject.settings.prod , если вам нужно для запуска команды для производственной среды.

В файлах prod.pyи local.py:

from .shared import *

DATABASE = {
    ...
}

и shared.pyфайл остается глобальным без конкретных конфигураций.

Фелипе Буччони
источник
3

построение ответа cs01:

если у вас возникли проблемы с переменной окружения, установите ее значение в строку (например, я сделал DJANGO_DEVELOPMENT="true" ).

Я также изменил рабочий процесс файла cs01 следующим образом:

#settings.py
import os
if os.environ.get('DJANGO_DEVELOPMENT') is not None:
    from settings_dev import * 
else:
    from settings_production import *
#settings_dev.py
development settings go here
#settings_production.py
production settings go here

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

Примечание: в Python 3 к импортированным файлам необходимо добавить .(например, from .settings_dev import *)

Брайан Ли
источник
1

Если вы хотите сохранить 1 файл настроек, а ваша операционная система разработки отличается от производственной операционной системы, вы можете поместить его в конец файла settings.py:

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
    # some special setting here for when I'm on my prod server
elif platform == "darwin":
    # OS X
    # some special setting here for when I'm developing on my mac
elif platform == "win32":
    # Windows...
    # some special setting here for when I'm developing on my pc

Подробнее: Как проверить операционную систему в Python?

пользователь
источник
1

Кажется, на этот вопрос есть ответ, однако метод, который я использую в сочетании с контролем версий, следующий:

Установите файл env.py в том же каталоге, что и настройки в моей локальной среде разработки, которую я также добавляю в .gitignore:

env.py:

#!usr/bin/python

DJANGO_ENV = True
ALLOWED_HOSTS = ['127.0.0.1', 'dev.mywebsite.com']

.gitignore:

mywebsite/env.py

settings.py:

if os.path.exists(os.getcwd() + '/env.py'):
    #env.py is excluded using the .gitignore file - when moving to production we can automatically set debug mode to off:
    from env import *
else:
    DJANGO_ENV = False

DEBUG = DJANGO_ENV

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


источник
Самое простое решение. Также можно определить все в Configклассе внутри env.pyфайла. Тогда вместо import *модуля модуль можно импортировать с помощью from env import Config. Таким образом, вам также не нужно использовать эту if os.pathcheck, что значительно упрощает все это.
Siddharth Pant
0

Использовать settings.pyдля производства. В том же каталоге создайте settings_dev.pyдля переопределений.

# settings_dev.py

from .settings import * 

DEBUG = False

На машине разработчика запустите приложение Django с помощью:

DJANGO_SETTINGS_MODULE=<your_app_name>.settings_dev python3 manage.py runserver

На прод-машине запускай как будто только что settings.pyи ничего больше.

ПРЕИМУЩЕСТВА

  1. settings.py (используется для производства) полностью не зависит от того, существуют ли какие-либо другие среды.
  2. Чтобы увидеть разницу между prod и dev, достаточно посмотреть в одном месте - settings_dev.py. Не нужно собирать разрозненные конфигурации settings_prod.py, settings_dev.pyи settings_shared.py.
  3. Если кто-то добавит параметр в вашу конфигурацию продукта после устранения неполадок производственной проблемы, вы можете быть уверены, что он также появится в вашей конфигурации разработчика (если это явно не отменено). Таким образом будет сведено к минимуму расхождение между разными конфигурационными файлами.
Алексей Юрша
источник
0

Для проблемы с настройкой файлов я выбираю копировать

Project
   |---__init__.py   [ write code to copy setting file from subdir to current dir]
   |---settings.py  (do not commit this file to git)
   |---setting1_dir
   |         |--  settings.py
   |---setting2_dir
   |         |--  settings.py

Когда вы запустите django, будет запущен __init__py. На этот раз settings.py in setting1_dirбуду заменять settings.py in Project.

Как выбрать другой env?

  • изменять __init__.pyнапрямую.
  • создайте файл bash для изменения __init__.py.
  • измените env в Linux, а затем позвольте __init__.pyпрочитать эту переменную.

Зачем использовать этот способ?

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

Если вы не хотите видеть все эти детали, вы можете разделить проект на две части.

  1. сделайте свой небольшой инструмент, такой как Spring Initializr, просто для настройки вашего проекта. (сделайте что-то вроде копирования файла)
  2. код вашего проекта
kyakya
источник
0

Я использую другой файл app.yaml для изменения конфигурации между средами в движке облачных приложений Google.

Вы можете использовать это для создания прокси-соединения в своей команде терминала:

./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:1433

https://cloud.google.com/sql/docs/sqlserver/connect-admin-proxy#macos-64-bit

Файл: app.yaml

# [START django_app]
service: development
runtime: python37

env_variables:
  DJANGO_DB_HOST: '/cloudsql/myproject:myregion:myinstance'
  DJANGO_DEBUG: True

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
# [END django_app]
Родриго Гросси
источник
-1

Это мое решение с разными средами для разработчиков, тестов и продуктов.

import socket

[...]

DEV_PC = 'PC059'
host_name = socket.gethostname()

if host_name == DEV_PC:
   #do something
   pass
elif [...]
Массимо Вариоло
источник