Jak zarządzać ustawieniami lokalnymi vs produkcyjnymi w Django?

Jaki jest zalecany sposób obsługi ustawień dla lokalnego rozwoju i serwera produkcyjnego? Niektóre z nich (jak stałe, itp.) mogą być zmieniane/dostępne w obu, ale niektóre z nich (jak ścieżki do plików statycznych) muszą pozostać inne, a zatem nie powinny być nadpisywane za każdym razem, gdy nowy kod jest wdrażany.

Obecnie dodaję wszystkie stałe do settings.py. Ale za każdym razem, gdy zmieniam jakąś stałą lokalnie, muszę ją skopiować na serwer produkcyjny i edytować plik dla zmiany specyficzne dla produkcji... :(

Edit: wygląda na to, że nie ma standardowej odpowiedzi na to pytanie, zaakceptowałem najpopularniejszą metodę.

Author: guaka, 2009-10-26

20 answers

W settings.py:

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

Możesz nadpisać to, co potrzebne w local_settings.py; powinno to pozostać poza kontrolą wersji. Ale skoro wspominasz o kopiowaniu to zgaduję, że nie używasz żadnego ;)

 118
Author: ohnoes,
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
2014-07-29 10:38:48

Dwie gałki Django: najlepsze praktyki dla Django 1.5 sugeruje użycie kontroli wersji dla plików ustawień i przechowywanie plików w osobnym katalogu:

project/
    app1/
    app2/
    project/
        __init__.py
        settings/
            __init__.py
            base.py
            local.py
            production.py
    manage.py

Plik base.py zawiera wspólne ustawienia (takie jak MEDIA_ROOT lub ADMIN), podczas gdy local.py i production.py mają ustawienia specyficzne dla witryny:

W pliku bazowym settings/base.py:

INSTALLED_APPS = (
    # common apps...
)

W pliku ustawień lokalnego rozwoju settings/local.py:

from project.settings.base import *

DEBUG = True
INSTALLED_APPS += (
    'debug_toolbar', # and other apps for local development
)

W pliku ustawienia produkcji settings/production.py:

from project.settings.base import *

DEBUG = False
INSTALLED_APPS += (
    # other apps for production site
)

Po uruchomieniu django dodajesz opcję --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

Autorzy książki umieścili również przykładowy szablon projektu na Githubie.

 262
Author: Rudolf Olah,
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
2014-12-18 01:09:36

Zamiast settings.py Użyj tego układu:

.
└── settings/
    ├── __init__.py  <= not versioned
    ├── common.py
    ├── dev.py
    └── prod.py

common.py tam mieszka większość twojej konfiguracji.

prod.py importuje wszystko z common i nadpisuje wszystko, czego potrzebuje do nadpisania: {]}

from __future__ import absolute_import # optional, but I like it
from .common import *

# Production overrides
DEBUG = False
#...

Podobnie, dev.py importuje wszystko z common.py i nadpisuje wszystko, co jest potrzebne do nadpisania.

Wreszcie, __init__.py to miejsce, w którym decydujesz, które ustawienia chcesz załadować, a także miejsce, w którym przechowujesz tajemnice (dlatego ten plik nie powinien być Wersja):

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

To, co lubię w tym rozwiązaniu, to:

    Wszystko jest w Twoim systemie wersjonowania, z wyjątkiem sekretów]}
  1. większość konfiguracji jest w jednym miejscu: common.py.
  2. prod-specific things go in prod.py, dev-specific things go in dev.py. To proste.
  3. możesz nadpisać rzeczy z common.py w prod.py lub dev.py, i możesz nadpisać wszystko w __init__.py.
  4. To prosty python. Żadnych włamań.
 61
Author: MiniQuark,
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
2013-03-09 19:48:26

Używam nieco zmodyfikowanej wersji stylu" if DEBUG " ustawień, które opublikował Harper Shelby. Oczywiście w zależności od środowiska (win / linux / etc.) kod może wymagać trochę podrasowania.

W przeszłości używałem "if DEBUG", ale okazało się, że czasami muszę wykonać testowanie z deubg ustawionym na False. Co naprawdę chciałem odróżnić, czy środowisko jest produkcja czy rozwój, co dało mi swobodę wyboru poziomu debugowania.

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'

I ' d still rozważ ten sposób ustawienia pracy w toku. Nie widziałem żadnego sposobu na obsługę ustawień Django, który obejmował wszystkie bazy i jednocześnie nie był całkowitym kłopotem w konfiguracji(nie jestem w dół z metodami plików ustawień 5X).

 19
Author: T. Stone,
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
2009-10-26 18:47:16

Używam settings_local.py i a settings_production.py. po wypróbowaniu kilku opcji odkryłem, że łatwo jest tracić czas na złożone rozwiązania, gdy po prostu posiadanie dwóch plików ustawień jest łatwe i szybkie.

Kiedy używasz mod_python/mod_wsgi dla Twojego projektu Django musisz skierować go do swojego pliku ustawień. Jeśli wskażesz to na app/settings_local.py na lokalnym serwerze i app/settings_production.py na serwerze produkcyjnym życie staje się łatwe. Wystarczy edytować odpowiednie plik ustawień i uruchom ponownie serwer (Django development server uruchomi się automatycznie).

 14
Author: Kai,
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
2009-10-26 18:12:30

Zarządzam konfiguracjami za pomocą django-split-settings .

Jest to zamiennik drop - in dla domyślnych ustawień. Jest prosty, ale konfigurowalny. Refaktoryzacja ustawień exisitng nie jest wymagana.

Oto mały przykład (plik 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()
    )
To wszystko.

Update

Napisałem post na blogu o zarządzaniu ustawieniami django za pomocą django-split-sttings. Zobacz!

 7
Author: sobolevn,
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-07-08 10:31:27

Problem z większością tych rozwiązań polega na tym, że albo masz swoje ustawienia lokalne przedzwykłymi, albo po nimi.

Więc nie da się nadpisać takich rzeczy jak

    ENV określa adresy dla puli memcached, a w głównym pliku ustawień ta wartość jest używana do konfiguracji backendu pamięci podręcznej W przeciwieństwie do innych programów, które nie są dostępne w env, nie można ich używać.]}

W o tej samej porze.

Jedno rozwiązanie może być zaimplementowane przy użyciu plików konfiguracyjnych w stylu " ini " z klasą ConfigParser. Obsługuje wiele plików, leniwa interpolacja ciągów, wartości domyślne i wiele innych gadżetów. Po załadowaniu wielu plików można załadować więcej plików, a ich wartości zastąpią poprzednie, jeśli takie istnieją.

Ładujesz jeden lub więcej plików konfiguracyjnych, w zależności od adresu maszyny, zmiennych środowiskowych, a nawet wartości wcześniej załadowanych plików konfiguracyjnych. Wtedy po prostu używasz przetwarzanych wartości, aby wypełnić ustawienia.

Jedną ze strategii, którą z powodzeniem zastosowałem, było:

  • załaduj domyślny plik defaults.ini
  • Sprawdź nazwę Maszyny i załaduj wszystkie pliki, które pasowały do odwróconego FQDN, od najkrótszego dopasowania do najdłuższego dopasowania (więc załadowałem net.ini, następnie net.domain.ini, następnie net.domain.webserver01.ini, każdy z nich może nadpisywać poprzednie wartości). To konto również dla maszyn programistów, więc każdy z nich może skonfigurować swój preferowany sterownik bazy danych, itd. dla rozwoju lokalnego
  • sprawdź, czy jest zadeklarowana "nazwa klastra", a w takim przypadku load cluster.cluster_name.ini, który może zdefiniować takie rzeczy, jak baza danych i adresy IPS pamięci podręcznej

Jako przykład czegoś, co możesz osiągnąć za pomocą tego, możesz zdefiniować wartość "subdomeny" per-env, która jest następnie używana w domyślnych ustawieniach (jako hostname: %(subdomain).whatever.net), aby zdefiniować wszystkie niezbędne nazwy hostów i rzeczy cookie, które django potrzebuje do działania.

To jest tak suche jak mogłem, większość (istniejących) plików miała tylko 3 lub 4 ustawienia. Oprócz tego musiałem zarządzać konfiguracją klienta, więc istniał dodatkowy zestaw plików konfiguracyjnych (takich jak nazwy baz danych, użytkownicy i hasła, przypisana subdomena itp.), jeden lub więcej na klienta.

Można skalować to tak nisko lub tak wysoko, jak to konieczne, po prostu umieścić w pliku konfiguracyjnym klucze, które chcesz skonfigurować dla środowiska, a gdy pojawi się potrzeba nowego config, umieścić poprzednią wartość w domyślnym config i zastąpić go, gdzie konieczne.

Ten system okazał się niezawodny i dobrze współpracuje z kontrolą wersji. Był używany przez długi czas do zarządzania dwoma oddzielnymi klastrami aplikacji (15 lub więcej oddzielnych instancji strony django na maszynę), z ponad 50 klientami, gdzie klastry zmieniały rozmiar i członków w zależności od nastroju sysadmina...

 6
Author: rewritten,
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-03-01 14:18:02

Pamiętaj, że settings.py to plik z kodem na żywo. Zakładając, że nie masz ustawionego DEBUGA na produkcji (co jest najlepszą praktyką), możesz zrobić coś w stylu:

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

Dość proste, ale teoretycznie możesz przejść do dowolnego poziomu złożoności w oparciu o wartość DEBUG-lub dowolną inną zmienną lub kontrolę kodu, której chcesz użyć.

 4
Author: Harper Shelby,
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
2009-10-26 18:05:19

Pracuję również z Laravelem i podoba mi się tam implementacja. Starałem się go naśladować i połączyć z rozwiązaniem zaproponowanym przez T. Stone ' A (patrz wyżej):

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
Może coś takiego ci pomoże.
 4
Author: Robert Kuzma,
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
2014-08-04 08:38:05

Moje rozwiązanie tego problemu jest również w pewnym sensie mieszanką niektórych rozwiązań już wymienionych tutaj:

  • przechowuję plik o nazwie local_settings.py, który ma zawartość USING_LOCAL = True w dev i USING_LOCAL = False w prod
  • W settings.py wykonuję import na tym pliku, aby uzyskać USING_LOCAL Ustawienie

Wtedy bazuję na tym wszystkie moje ustawienia zależne od środowiska:

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

Wolę to od posiadania dwóch oddzielnych settings.py pliki, które muszę zachować, ponieważ mogę zachować moje ustawienia w jednym plik łatwiejszy niż ich rozłożenie na kilka plików. W ten sposób, kiedy aktualizuję ustawienie, nie zapominam zrobić tego dla obu środowisk.

Oczywiście, że każda metoda ma swoje wady i ta nie jest wyjątkiem. Problem polega na tym, że nie mogę nadpisać pliku local_settings.py za każdym razem, gdy wprowadzam zmiany do produkcji, co oznacza, że nie mogę po prostu skopiować wszystkich plików na ślepo, ale z tym mogę żyć.

 3
Author: Miguel Ventura,
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
2009-10-26 20:10:27

W większości moich projektów stosuję następujący wzór:

  1. Utwórz settings_base.py gdzie przechowuję Ustawienia wspólne dla wszystkich środowisk
  2. ilekroć potrzebuję użyć nowego środowiska o określonych wymaganiach, tworzę nowy plik ustawień (np. settings_local.py), który dziedziczy zawartość settings_base.py i nadpisuje / dodaje odpowiednie zmienne ustawień (from settings_base import *)

(do uruchomienia manage.py w pliku ustawień niestandardowych wystarczy użyć opcji polecenia --settings: manage.py <command> --settings=settings_you_wish_to_use.py)

 3
Author: dzida,
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
2011-04-03 09:53:07

Używam odmiany tego, o czym jpartogi wspomniałem powyżej, która wydaje mi się nieco krótsza:

import platform
from django.core.management import execute_manager 

computername = platform.node()

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

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

W zasadzie na każdym komputerze (rozwojowym lub produkcyjnym) mam odpowiednie hostname_settings.py plik ładowany dynamicznie.

 3
Author: stratosgear,
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
2011-04-06 19:48:52

Istnieje również Django Classy Settings. Osobiście jestem jej wielkim fanem. Jest zbudowany przez jedną z najbardziej aktywnych osób na IRC Django. Do ustawiania rzeczy używasz zmiennych środowiskowych.

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

 3
Author: Emett Speer,
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-02-21 17:56:20

TL;DR: sztuką jest zmodyfikować os.environment przed zaimportowaniem settings/base.py do dowolnego settings/<purpose>.py, to znacznie uprości sprawę.


Sama myśl o tych wszystkich splatających się plikach przyprawia mnie o ból głowy. Łączenie, importowanie (czasami warunkowo), nadpisywanie, łatanie tego, co zostało już ustawione w przypadku zmiany ustawienia DEBUG później. Co za koszmar!

Przez lata przechodziłem przez różne rozwiązania. Wszystkie one[40]} trochę [41]} działają, ale są tak bolesne w zarządzaniu. WTF! Czy naprawdę potrzebujemy tych kłopotów? Zaczęliśmy od jednego pliku {[10] }. Teraz potrzebujemy dokumentacji tylko po to, aby poprawnie połączyć wszystkie te razem w odpowiedniej kolejności!

Mam nadzieję, że w końcu trafiłem w (mój) słodki punkt z poniższym rozwiązaniem.

Podsumujmy cele (niektóre wspólne, niektóre moje)]}
  1. Zachowaj sekrety w tajemnicy - nie przechowuj ich w repo.

  2. Ustawianie / odczytywanie kluczy i sekretów poprzez ustawienia środowiska, 12 styl .

  3. Miej rozsądne domyślne ustawienia awaryjne. Idealnie dla rozwoju lokalnego nie potrzebujesz niczego więcej oprócz domyślnych.

  4. ...ale staraj się zapewnić bezpieczeństwo produkcji domyślnej. Lepiej przegapić lokalne nadpisanie ustawień, niż trzeba pamiętać, aby dostosować domyślne ustawienia bezpieczne dla produkcji.

  5. Posiadają możliwość włączania/wyłączania DEBUG w sposób, który może mieć wpływ na inne ustawienia (np. za pomocą javascript skompresowanego lub nie).

  6. Przełączanie między ustawieniami celu, takimi jak local/testing/staging/production, powinno opierać się tylko na DJANGO_SETTINGS_MODULE, nic więcej.

  7. ...ale Zezwalaj na dalszą parametryzację poprzez ustawienia środowiska, takie jak DATABASE_URL.

  8. ...pozwól im również korzystać z różnych ustawień celu i uruchamiaj je lokalnie obok siebie, np. konfiguracja produkcji na lokalnej maszynie deweloperskiej, aby uzyskać dostęp do bazy danych produkcji lub skompresowanego stylu testu dymu prześcieradła.

  9. Błąd, jeśli zmienna środowiskowa nie jest jawnie ustawiona( wymaga minimum pustej wartości), szczególnie w produkcji, np. EMAIL_HOST_PASSWORD.

  10. Odpowiadaj na domyślne DJANGO_SETTINGS_MODULE ustawione w manage.py podczas django-Admin startproject

  11. Ogranicz warunki do minimum, jeśli warunek jest typem środowiska (np. dla pliku dziennika zestawu produkcyjnego i jego rotacji), nadpisuje ustawienia w powiązanych Ustawieniach plik.

Do not

  1. Nie pozwól django odczytać ustawienia DJANGO_SETTINGS_MODULE z pliku.
    Ugh! Pomyśl o meta to jest. Jeśli potrzebujesz mieć plik (np. docker env) przeczytaj to w środowisku, zanim rozpoczniesz proces django.

  2. Nie nadpisuj DJANGO_SETTINGS_MODULE w kodzie projektu / aplikacji, np. na podstawie nazwy hosta lub nazwy procesu.
    Jeśli jesteś leniwy, aby ustawić zmienną środowiskową (jak dla setup.py test) zrób to w narzędzia tuż przed uruchomieniem kodu projektu.

  3. Unikaj magii i łatania tego, jak django odczytuje swoje ustawienia, przetworz ustawienia, ale nie przeszkadzaj później.

  4. Żadnych skomplikowanych logicznych bzdur. Konfiguracja powinna być ustalona i zmaterializowana, a nie obliczana w locie. Zapewnienie domyślnych opcji awaryjnych jest wystarczająca logika.
    Czy naprawdę chcesz debugować, dlaczego lokalnie masz poprawny zestaw ustawień, ale w produkcji na zdalnym serwerze, na jednej ze stu maszyn, coś obliczane inaczej? Oh! Testy jednostkowe? Dla ustawień? Poważnie?

Rozwiązanie

Moja strategia składa się z doskonałego django-Environ używanego z plikami stylów ini, dostarczanie os.environment domyślnych dla rozwoju lokalnego, niektórych minimalnych i krótkich settings/<purpose>.py plików, które mają import settings/base.py po os.environment został ustawiony z pliku INI. To skutecznie daje nam rodzaj zastrzyku ustawień.

Sztuczka polega na zmodyfikuj os.environment przed zaimportowaniem settings/base.py.

Aby zobaczyć pełny przykład, wykonaj repo: 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

Ustawienia/.env

A defaults for local development. Tajny plik, w którym najczęściej ustawiane są wymagane zmienne środowiskowe. Ustaw je na puste, jeśli nie są wymagane w rozwoju lokalnym. Zapewniamy domyślne tutaj, a nie w settings/base.py, aby zawieść na każdej innej maszynie, jeśli brakuje z środowisko.

Settings/local.py

To, co się tutaj dzieje, to Ładowanie środowiska z settings/.env, a następnie importowanie wspólnych ustawień od settings/base.py. Następnie możemy obejść kilka, aby ułatwić lokalny rozwój.

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

Settings/production.py

W przypadku produkcji nie powinniśmy oczekiwać pliku środowiska, ale łatwiej jest go mieć, jeśli coś testujemy. Ale w każdym razie, lest dostarcza kilka domyślnych wartości inline, więc settings/base.py może odpowiednio zareagować.

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

Głównym punktem zainteresowania są tutaj DEBUG i ASSETS_DEBUG nadrzędne, będą one stosowane do Pythona os.environ tylko wtedy, gdy brakuje ich w środowisku i Pliku.

Będą to nasze domyślne ustawienia produkcyjne, nie trzeba ich umieszczać w środowisku lub pliku, ale w razie potrzeby można je przesłonić. Super!

Settings/base.py

To są Twoje głównie waniliowe ustawienia django, z kilkoma warunkami i wieloma czytaniem ich ze środowiska. Prawie wszystko jest tutaj, zachowując wszystkie zamierzone środowiska spójne i jak najbardziej podobne.

Główne różnice są poniżej (mam nadzieję, że są oczywiste):

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',)
[[34]}ostatni kawałek pokazuje moc tutaj. ASSETS_DEBUG mA sensowną domyślną, które może być nadpisane w settings/production.py, a nawet to, które może być nadpisane przez ustawienie środowiska! Yay!

W efekcie mamy mieszaną hierarchię znaczenie:

  1. settings/.py - ustawia domyślne wartości na podstawie celu, nie przechowuje tajemnic
  2. settings/base.py - jest w większości kontrolowany przez środowisko
  3. ustawienia środowiska procesowego-12 factor baby!
  4. ustawienia/.env-local defaults for easy startup
 3
Author: Janusz Skonieczny,
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-15 11:45:33

Rozróżniam to w manage.py i stworzył dwa oddzielne pliki ustawień: local_settings.py oraz prod_settings.py.

W manage.py sprawdzam czy serwer jest lokalny czy produkcyjny. Jeśli jest to serwer lokalny to załaduje się local_settings.py i jest to serwer produkcyjny, który by się załadował prod_settings.py. w zasadzie tak by to wyglądało:

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

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

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

Okazało się, że łatwiej jest oddzielić plik ustawień na dwa oddzielne pliki, zamiast robić wiele ifs wewnątrz pliku ustawień.

 1
Author: Joshua Partogi,
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
2009-10-27 11:52:22

Jako alternatywa dla utrzymania innego pliku, jeśli wiil: Jeśli używasz git lub innych VC do wysyłania kodów z lokalnego serwera, możesz dodać plik ustawień .gitignore.

To pozwoli Ci mieć różne treści w obu miejscach bez żadnego problemu. Więc na serwerze można skonfigurować niezależną wersję settings.py a wszelkie zmiany wprowadzone na lokalnym serwerze nie odzwierciedlają się na serwerze i vice versa.

DODATKOWO usunie settings.py Plik z github również, wielki błąd, który widziałem wielu początkujących robi.

 1
Author: sprksh,
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-05-03 06:15:30

Aby użyć innej konfiguracji settings w innym środowisku, Utwórz inny plik ustawień. I w skrypcie wdrożenia uruchom serwer za pomocą --settings=<my-settings.py> parametr, za pomocą którego można używać różnych ustawień w różnych środowiskach.

Korzyści z zastosowania tego podejścia :

  1. Twoje ustawienia będą modułowe w zależności od środowiska

  2. Możesz zaimportować master_settings.py zawierający podstawową konfigurację w environmnet_configuration.py i nadpisuje wartości, które chcesz zmienić w tym środowisku.

  3. Jeśli masz ogromny zespół, każdy programista może mieć swój własny local_settings.py, który może dodać do repozytorium kodu bez ryzyka modyfikacji konfiguracji serwera. Możesz dodać te ustawienia lokalne do .gitnore, Jeśli używasz git lub .hginore, Jeśli używasz Mercurialdo kontroli wersji (lub innych). W ten sposób ustawienia lokalne nie będą nawet częścią rzeczywistej bazy kodu czysto.

 1
Author: Moinuddin Quadri,
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-11-09 22:40:13

1-Utwórz nowy folder wewnątrz aplikacji i nazwij go ustawieniami.

2-Teraz utwórz nowy plik init . py w nim i w nim napisz

    from .base import *

    try:

Od .import lokalny *

    except:

Pass

     try:

Od .import produkcji *

     except:

Pass

3-Utwórz trzy nowe pliki w nazwie folderu ustawienia local.py oraz production.py oraz base.py

4 - wewnątrz base.py Skopiuj całą zawartość poprzednich ustawień.folder p i zmień jego nazwę na coś różne powiedzmy old_settings.py

5-W base.py zmień ścieżkę BASE_DIR, aby wskazywała na nową ścieżkę Ustawienia

Stara ścieżka - > BASE_DIR = os./ align = "left" / dirname (os./ align = "left" / dirname (os./ align = "left" / abspath (Plik)))

Nowa ścieżka - > BASE_DIR = os./ align = "left" / dirname (os./ align = "left" / dirname (os./ align = "left" / dirname (os./ align = "left" / abspath (Plik)))

Teraz w ten sposób projekt dir może być zorganizowany i może być zarządzany wśród produkcji i rozwoju lokalnego.

 1
Author: Jack Ryan,
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-06-10 04:32:50

Moje ustawienia zostały podzielone w następujący sposób

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

Mamy 3 środowiska

  • dev
  • inscenizacja
  • produkcja

Teraz oczywiście inscenizacja i produkcja powinny mieć maksymalne możliwe podobne środowisko. Więc zatrzymaliśmy prod.py dla obu.

Ale był przypadek, w którym musiałem zidentyfikować działający serwer jest serwerem produkcyjnym. Odpowiedź @T. Stone ' A pomogła mi napisać czek w następujący sposób.

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

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


if any(host in PROD_HOSTS for host in ALLOWED_HOSTS):
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True  
 1
Author: Kishor Pawar,
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-12 16:39:47

Odpowiedzi tutaj okazały się bardzo pomocne. (Czy to zostało bardziej definitywnie rozwiązane? Ostatnia odpowiedź była rok temu.) Po rozważeniu wszystkich wymienionych podejść, wymyśliłem rozwiązanie, którego nie widziałem tutaj.

Moje kryteria to:

  • Wszystko powinno być pod kontrolą źródła. Nie lubię wiercących się kawałków.
  • najlepiej zachować ustawienia w jednym pliku. Zapominam rzeczy, jeśli nie patrzę prosto na nie:)
  • Brak ręcznych edycji do / align = "left" / Powinien być w stanie przetestować/wypchnąć/wdrożyć za pomocą jednego polecenia tkaniny.
  • unikaj wycieku ustawień programistycznych do produkcji.
  • trzymaj się jak najbliżej" standardowego " (*cough*) układu Django.

Myślałem, że włączenie komputera ma jakiś sens, ale potem zorientowałem się, że prawdziwym problemem są różne ustawienia dla różnych środowisk {9]} i miałem chwilę aha. Umieszczam ten kod na końcu mojego settings.py plik:

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'

W ten sposób aplikacja domyślnie ustawia ustawienia produkcyjne, co oznacza, że jesteś jawnie "na białej liście" środowiska programistycznego. O wiele bezpieczniej jest zapomnieć o ustawieniu zmiennej środowiskowej lokalnie, niż gdyby było odwrotnie i zapomniałeś ustawić coś w produkcji i pozwolić na użycie niektórych ustawień dev.

Gdy rozwija się lokalnie, albo z powłoki, albo wbash_profile czy gdziekolwiek:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(lub jeśli tworzysz na Windows, Ustaw przez Panel sterowania czy jak to się nazywa w dzisiejszych czasach... System Windows zawsze sprawiał, że był tak niejasny, że można było ustawiać zmienne środowiskowe.)

Dzięki takiemu podejściu ustawienia dev są w jednym (standardowym) miejscu i w razie potrzeby po prostu zastępują ustawienia produkcyjne. Wszelkie problemy z ustawieniami programistycznymi powinny być całkowicie bezpieczne, aby zaangażować się w kontrolę źródeł bez wpływu na produkcję.

 -3
Author: Jason Boyd,
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
2014-02-17 06:49:49