Django: Як керувати налаштуваннями розробки та виробництва?


129

Я розробляв базовий додаток. Тепер на етапі розгортання стало зрозуміло, що мені потрібні як локальні, так і виробничі налаштування.

Було б чудово знати наступне:

  • Як найкраще впоратися з налаштуваннями розробки та виробництва.
  • Як зберегти додатки, такі як django-debug-toolbar тільки в середовищі розробки.
  • Будь-які інші поради та найкращі практики щодо налаштувань розробки та розгортання.

Відповіді:


109

В DJANGO_SETTINGS_MODULEзмінної середовища управління , який файл настройок Django завантажить.

Отже, ви створюєте окремі файли конфігурації для відповідних середовищ (зауважте, що вони, звичайно, можуть бути як import *з окремого файлу "спільних налаштувань"), так і використовувати DJANGO_SETTINGS_MODULEдля керування, який з них використовувати.

Ось як:

Як зазначено в документації про Джанго:

Значення 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
Ісус Альмарал - Hackaprende

Це рішення, схоже, не відповідає дійсності для conda env. У середовищі conda немає бін / активації.
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 змінної, щоб використовувати його для запуску тестових випадків.
F.Tamy

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 за раз.


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.
Даніель Уоткінс

17

Ось так я це роблю в 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 = [...]
    ...

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']))

Імпортувати змінні, які потрібно змінити.

Цей запис у вікі має більше ідей щодо того, як розділити налаштування.


Дякую Бурхам! Під час розгортання програми мені просто потрібно видалити файл settings_dev, щоб побачити мої налаштування розгортання в дії?
Крістіан Робук

Так, або замініть імпорт наsettings_prod.py
Бурхан Халід

1
Редагування файлу master settings.py на розгортанні означає, що він зіткнеться з контролем версій, тому це не обов'язково найкращий шлях вперед. Я б сказав, що варіант Томаса Ороско найкращий - ви можете встановити DJANGO_SETTINGS_MODULE у своєму скрипті virtualenv postactivate або у вашому налаштуванні gunicorn або mod_wsgi
Стів Ялім

1
Можливо, слід зауважити, що ви ніколи не додаєте до керування джерелами файли, орієнтовані на етап. Я припускав, що розуміється, що ви не будете натискати на налаштування, що стосуються конкретного етапу проекту.
Бурхан Халід

Якщо ви використовуєте virtualenv, він, як правило, за замовчуванням налаштовує {{project_name}}. Отже, "налаштування" не будуть ключовими в sys.modules. Це буде "myproject.settings" (або будь-яка назва вашого проекту). Ви можете використовувати modname = "%s.settings" % ".".join(__name__.split('.')[:-1])повне ім'я модуля, а потім globals().update(vars(sys.modules[modname])). Я вважаю, що це добре працює для мене. Звичайно, відмова від програмного визначення імені модуля на користь рядка, ймовірно, спрацює і в більшості випадків.
Ерік

9

Я використовую дивовижні конфігурації джанго , і всі налаштування зберігаються в моїх 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як, наприклад, розробка, постановка та виробництво;
  • облікові дані не знаходяться в сховищі

Я сподіваюся, що це допомагає, просто дайте мені знати, якщо ви бачите якісь застереження з цим рішенням.


за умови , де 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це посилання (перли в UNIX або mklink в вікнах) , щоб 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 файл налаштувань, а ваша операційна система розробки відрізняється від вашої виробничої операційної системи, ви можете помістити це внизу вашої настройки.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. Таким чином, вам також не потрібно використовувати це, якщо os.pathперевірити, що робить це все набагато простішим.
Сіддхарт Пант

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. код вашого проекту

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 [...]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.