Django: jak zarządzać ustawieniami programistycznymi i produkcyjnymi?

Pracuję nad podstawową aplikacją. Teraz na etapie wdrażania stało się jasne, że potrzebuję zarówno ustawień lokalnych, jak i ustawień produkcyjnych.

Dobrze byłoby wiedzieć, co następuje:

  • jak najlepiej radzić sobie z ustawieniami rozwojowymi i produkcyjnymi.
  • Jak utrzymać aplikacje takie jak django-debug-toolbar tylko w środowisku deweloperskim.
  • Wszelkie inne wskazówki i najlepsze praktyki dotyczące ustawień rozwoju i wdrażania.
 147
Author: Kristian Roebuck, 2012-05-19

15 answers

The DJANGO_SETTINGS_MODULE zmienna środowiskowa określa, który plik ustawień zostanie załadowany przez Django.

Tworzysz więc oddzielne pliki konfiguracyjne dla odpowiednich środowisk (zauważ, że mogą one oczywiście zarówno import * z oddzielnego pliku "shared settings"), jak i używać DJANGO_SETTINGS_MODULE do kontrolowania, którego z nich użyć.

Oto jak:

Jak zaznaczono w dokumentacji Django:

Wartość DJANGO_SETTINGS_MODULE powinna znajdować się w składni ścieżki Pythona, np. mysite.ustawienia. Zauważ, że moduł ustawienia powinien znajdować się na ścieżce wyszukiwania importu Pythona.

Załóżmy więc, że utworzyłeś myapp/production_settings.py i myapp/test_settings.py w swoim repozytorium źródłowym.

W takim przypadku ustawisz odpowiednio DJANGO_SETTINGS_MODULE=myapp.production_settings, aby używać pierwszego i DJANGO_SETTINGS_MODULE=myapp.test_settings, aby używać drugiego.


Od teraz problem sprowadza się do ustawienia zmiennej środowiskowej DJANGO_SETTINGS_MODULE.

Ustawienie DJANGO_SETTINGS_MODULE za pomocą skryptu lub powłoki

Możesz następnie użyć skryptu bootstrap lub menedżer procesów, aby załadować poprawne ustawienia (poprzez ustawienie środowiska), lub po prostu uruchomić go z powłoki przed uruchomieniem Django: export DJANGO_SETTINGS_MODULE=myapp.production_settings.

Zauważ, że możesz uruchomić ten eksport w dowolnym momencie z powłoki-nie musi ona mieszkać w twoim .bashrc ani niczym innym.

Ustawienie DJANGO_SETTINGS_MODULE za pomocą menedżera procesów

Jeśli nie lubisz pisać skryptu bootstrap, który ustawia środowisko (i są bardzo dobre powody, aby tak myśleć!), Polecam korzystanie z procesu kierownik:


Na koniec zauważ, że możesz skorzystać ze zmiennej PYTHONPATH, aby zapisać ustawienia w zupełnie innej lokalizacji (np. na serwer produkcyjny, przechowujący je w /etc/). Pozwala to na oddzielenie konfiguracji od plików aplikacji. Możesz tego chcieć lub nie, zależy to od struktury aplikacji.

 117
Author: Thomas Orozco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-07 10:41:27

Domyślnie używaj ustawień produkcyjnych, ale Utwórz plik o nazwie settings_dev.py w tym samym folderze co plik settings.py. Dodaj tam przesłonięcia, takie jak DEBUG=True.

Na komputerze, który będzie używany do rozwoju, dodaj to do pliku ~/.bashrc:

export DJANGO_DEVELOPMENT=true

Na dole pliku settings.py Dodaj następujący tekst.

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

(zauważ, że w Pythonie należy unikać importowania *)

Domyślnie serwery produkcyjne niczego nie nadpisują. Zrobione!

W porównaniu do innych odpowiedzi, ta jest prostsza, ponieważ nie wymaga aktualizacji PYTHONPATH, ani Ustawienia DJANGO_SETTINGS_MODULE, które pozwala Ci pracować tylko nad jednym projektem django na raz.

 71
Author: cs01,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-27 18:17:38

Zazwyczaj mam jeden plik ustawień na środowisko i plik ustawień współdzielonych:

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

Każdy z moich plików środowiskowych ma:

try:
    from shared_settings import *
except ImportError:
    pass

Pozwala mi to w razie potrzeby zastąpić Wspólne Ustawienia(dodając modyfikacje poniżej tej zwrotki).

Następnie wybieram, których plików ustawień użyć, łącząc je z settings.py:

ln -s settings.development.py settings.py
 37
Author: Daniel Watkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-19 11:28:31

Tak to robię w 6 prostych krokach:

  1. Utwórz folder wewnątrz katalogu projektu i nadaj mu nazwę settings.

    struktura projektu:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
    
  2. Utwórz cztery pliki Pythona wewnątrz katalogu settings mianowicie __init__.py, base.py, dev.py i prod.py

    Pliki Ustawień:

    settings/
         __init__.py
         base.py
         prod.py
         dev.py 
    
  3. Otwórz __init__.py i wypełnij go następującym treść:

    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. Otwórz base.py i wypełnij go wszystkimi wspólnymi ustawieniami (które będą używane zarówno w produkcji, jak i w rozwoju.) na przykład:

    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. Otwórz dev.py i dołącz to, co jest specyficzne dla rozwoju, na przykład:

    dev.py:

    DEBUG = True
    ALLOWED_HOSTS = ['localhost']
    ...
    
  6. Otwórz prod.py i dołącz to, co jest produkcją specyficzną dla przykład:

    prod.py:

    DEBUG = False
    ALLOWED_HOSTS = ['www.example.com']
    LOGGING = [...]
    ...
    
 26
Author: Ahtisham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-06 10:40:16

Tworzy wiele plików settings*.py, ekstrapolując zmienne, które muszą ulec zmianie w danym środowisku. Następnie na końcu pliku master settings.py:

try:
  from settings_dev import *
except ImportError:
  pass

Zachowujesz oddzielne pliki settings_* dla każdego etapu.

Na górze pliku settings_dev.py dodaj to:

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

Aby zaimportować zmienne, które należy zmodyfikować.

Ten wpis wiki zawiera więcej pomysłów na podzielenie ustawień.

 11
Author: Burhan Khalid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-19 10:30:56

Używam awesome django-konfiguracje , a wszystkie ustawienia są przechowywane w moim 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

Aby skonfigurować projekt Django, podążałem za docs.

 11
Author: Riccardo Leschiutta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-14 20:56:44

Oto podejście, które stosujemy:

  • A settings moduł do dzielenia ustawień na wiele plików dla czytelności ;
  • plik .env.json do przechowywania poświadczeń i parametrów, które chcemy wykluczyć z naszego repozytorium git lub które są specyficzne dla środowiska;
  • an env.py file to read the .env.json file

Biorąc pod uwagę następującą strukturę:

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

Z .env.json Jak:

{
    "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",
}

I 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()

Możemy mieć następujące ustawienia:

<!-- 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',
    }
}

Korzyści płynące z tego rozwiązania to:

  • poświadczenia i konfiguracje specyficzne dla użytkownika dla lokalnego rozwoju bez modyfikowania repozytorium git;
  • konfiguracja specyficzna dla środowiska, możesz mieć na przykład trzy różne środowiska z trzema różnymi .env.json Jak dev, stagging i produkcja ;
  • dane uwierzytelniające nie są w repozytorium

Mam nadzieję, że to pomoże, pozwól mi wiedz, czy widzisz jakieś zastrzeżenia dotyczące tego rozwiązania.

 8
Author: Charlesthk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 21:57:20

Używam struktury plików:

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

Więc {[2] } jest łączem (ln w Unixie lub mklink w windows) do local.py lub może być do prod.py więc konfiguracja jest nadal w module project.settings jest czysta i zorganizowana, a jeśli chcesz użyć konkretnego config możesz użyć zmiennej środowiskowej DJANGO_SETTINGS_MODULE do project.settings.prod jeśli chcesz uruchomić polecenie dla środowiska produkcyjnego.

W plikach prod.py i local.py:

from .shared import *

DATABASE = {
    ...
}

I shared.py Plik zachowuje się jako globalny bez określonego configs.

 4
Author: Felipe Buccioni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-16 18:44:48

Budowanie z cs01 ' s odpowiedź:

Jeśli masz problemy ze zmienną środowiskową, ustaw jej wartość na łańcuch znaków (np. zrobiłem DJANGO_DEVELOPMENT="true").

Zmieniłem również przepływ plików cs01 w następujący sposób:

#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

W ten sposób Django nie musi czytać całego pliku ustawień przed uruchomieniem odpowiedniego pliku ustawień. To rozwiązanie jest przydatne, jeśli Twój plik produkcyjny potrzebuje rzeczy, które są tylko na twoim serwerze produkcyjnym.

Uwaga: w Pythonie 3 importowane pliki trzeba mieć dopisane . (np. from .settings_dev import *)

 3
Author: Brian Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-24 14:03:55

Jeśli chcesz zachować 1 plik ustawień, a Twój system operacyjny rozwoju jest inny niż system operacyjny produkcji, możesz umieścić go na dole swojego 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

Read more: Jak sprawdzić system operacyjny w Pythonie?

 2
Author: User,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:19

Wydaje się, że odpowiedź została udzielona, jednak metoda, której używam w połączeniu z kontrolą wersji, jest następująca:

Setup a env.py plik w tym samym katalogu co Ustawienia w moim lokalnym środowisku programistycznym, do którego również dodaję .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
Po prostu uważam, że to działa i jest o wiele bardziej eleganckie - z env.py łatwo jest zobaczyć nasze lokalne zmienne środowiskowe i możemy obsłużyć to wszystko bez wielokrotności settings.py pliki lub podobne. Metoda ta pozwala na używanie różnego rodzaju lokalnych zmiennych środowiskowych, których nie chcemy ustawiać na naszym serwerze produkcyjnym. Wykorzystanie .gitignore poprzez kontrolę wersji również wszystko jest bezproblemowo zintegrowane.
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-16 17:53:14

Użyj settings.py do produkcji. W tym samym katalogu Utwórz settings_dev.py dla nadpisań.

# settings_dev.py

from .settings import * 

DEBUG = False

Na maszynie deweloperskiej uruchom swoją aplikację Django z:

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

Na maszynie prod działa tak, jakbyś miał settings.py i nic więcej.

Zalety

  1. settings.py (używany do produkcji) jest całkowicie agnostyczny wobec faktu, że istnieją jakiekolwiek inne środowiska.
  2. aby zobaczyć różnicę między prod I dev wystarczy spojrzeć na jedną lokalizację - settings_dev.py. Nie. trzeba zebrać konfiguracje rozrzucone po settings_prod.py, settings_dev.py i settings_shared.py.
  3. Jeśli ktoś doda ustawienie do twojej konfiguracji prod po rozwiązaniu problemu z produkcją, możesz mieć pewność, że pojawi się ono również w Twojej konfiguracji dev (chyba że zostanie wyraźnie nadpisane). W ten sposób rozbieżność między różnymi plikami konfiguracyjnymi zostanie zminimalizowana.
 1
Author: Alex Yursha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-25 10:16:34

W przypadku problemu z ustawieniem plików, wybieram skopiowanie

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

Kiedy uruchomisz django,__init _ _ py zostanie uruchomiony. W tym momencie settings.py in setting1_dir zastąpi settings.py in Project.

Jak wybrać inny env?

  • zmodyfikuj __init__.py bezpośrednio.
  • Utwórz plik bash, aby zmodyfikować __init__.py.
  • zmodyfikuj env w Linuksie, a następnie pozwól __init__.py odczytać tę zmienną.

Dlaczego używać w ten sposób?

Ponieważ nie lubię tak wielu plików w tym samym katalogu, zbyt wiele plików będzie mylić innych partnerów i nie bardzo dobrze dla IDE.(IDE nie może znaleźć pliku, którego używamy)

Jeśli nie chcesz widzieć wszystkich tych szczegółów, możesz podzielić projekt na dwie części.

  1. Stwórz małe narzędzie, takie jak Spring Initializr, tylko do konfiguracji projektu.(do sth like copy file)
  2. Twój kod projektu
 1
Author: kyakya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-09 05:45:57

Używam innej aplikacji.plik yaml do zmiany konfiguracji między środowiskami w Google cloud App engine.

Możesz użyć tego do utworzenia połączenia proxy w poleceniu terminal:

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

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

Plik: 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]
 0
Author: Rodrigo Grossi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-23 09:51:45

To jest moje rozwiązanie, z różnymi środowiskami dla dev, test i prod

import socket

[...]

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

if host_name == DEV_PC:
   #do something
   pass
elif [...]
 -1
Author: Massimo Variolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-03 09:31:39