TL; DR: hile değiştirmektir os.environment
İçe aktarmadan önce settings/base.py
herhangi settings/<purpose>.py
, bu işleri bir hayli kolaylaştıracak.
Tüm bu iç içe geçmiş dosyaları düşünmek başım ağrıyor. DEBUG
Daha sonra değiştiğinde ayarlanmış olanları birleştirme, içe aktarma (bazen koşullu olarak), geçersiz kılma, yama . Ne kabustu ama!
Yıllar boyunca tüm farklı çözümlerden geçtim. Hepsi biraz işe yarıyor, ama yönetmek çok acı verici. O NE LAN! Tüm bu güçlüklere gerçekten ihtiyacımız var mı? Sadece bir settings.py
dosya ile başladık . Şimdi tüm bunları doğru bir şekilde doğru bir şekilde bir araya getirmek için bir dokümana ihtiyacımız var!
Umarım sonunda (benim) tatlı noktaya aşağıdaki çözümle vurdum.
Hedefleri özetleyelim (bazıları ortak, bazıları benim)
Sırları bir sır olarak saklayın - onları bir depoda saklamayın!
Ortam ayarları, 12 faktör stili ile anahtarları ve sırları ayarlayın / okuyun .
Mantıklı yedek varsayılanlara sahip olun. İdeal olarak yerel kalkınma için varsayılanların yanında başka bir şeye ihtiyacınız yoktur.
… Ama varsayılan üretimi güvende tutmaya çalışın. Varsayılan ayarları üretim için güvenli olarak ayarlamayı hatırlamak zorunda kalmaktan ziyade, yerel olarak bir ayar geçersiz kılmayı kaçırmak daha iyidir.
DEBUG
Diğer ayarlar üzerinde etkili olabilecek bir şekilde açma / kapama yeteneğine sahip olma (örn. Javascript'i sıkıştırılmış veya kullanmama).
Yerel / test / aşamalandırma / üretim gibi amaç ayarları arasında geçiş yapmak, yalnızca DJANGO_SETTINGS_MODULE
başka bir şeye dayanmamalıdır .
… Ancak gibi ortam ayarları ile daha fazla parametrelendirmeye izin verin DATABASE_URL
.
… Ayrıca farklı amaç ayarları kullanmalarına ve bunları yan yana yerel olarak çalıştırmalarına izin verin, örn. üretim veritabanına veya duman testi sıkıştırılmış stil sayfalarına erişmek için yerel geliştirici makinesinde üretim kurulumu.
Bir ortam değişkeni, özellikle üretimde, örneğin, açık bir şekilde ayarlanmamışsa (minimumda boş bir değer gerektirir) başarısız olur. EMAIL_HOST_PASSWORD
.
Django-admin startprojectDJANGO_SETTINGS_MODULE
sırasında manage.py içinde ayarlanan varsayılana yanıt verin
Koşul ise, minimumda conditionals tutun amaçlı çevre tipi (örn. Üretim seti günlük dosyası ve 's dönüş için), ilişkili amaçlı ayarlar dosyasındaki ayarları geçersiz kılar.
Yapma
Django'nun bir dosyadan DJANGO_SETTINGS_MODULE ayarını okumasına izin vermeyin.
Ihh! Bunun ne kadar meta olduğunu düşünün. Bir dosyaya (docker env gibi) ihtiyacınız varsa, bir django işlemine başlamadan önce bu ortamı okuyunuz.
Proje / uygulama kodunuzdaki DJANGO_SETTINGS_MODULE'u geçersiz kılınmayın, örn. ana bilgisayar adı veya işlem adına göre.
Ortam değişkenini (gibi setup.py test
) ayarlamak için tembelseniz, proje kodunuzu çalıştırmadan hemen önce takım içinde bunu yapın.
Django'nun ayarlarını nasıl okuduğuna dair sihir ve yamalardan kaçının, ayarları önceden işleyin, ancak daha sonra müdahale etmeyin.
Karmaşık mantık tabanlı saçmalık yok. Konfigürasyon sabitlenmeli ve anında hesaplanmadan gerçekleştirilmelidir. Burada geri dönüş varsayılanları sağlamak yeterli bir mantıktır.
Gerçekten hata ayıklamak istiyor musunuz, neden yerel olarak doğru ayar kümeniz var, ancak uzak bir sunucuda, yüz makineden birinde, farklı bir şekilde hesaplanan bir şey üretiliyor? Ah! Birim testleri? Ayarlar için? Ciddi anlamda?
Çözüm
Stratejim, stil dosyaları ile kullanılan , yerel geliştirme için varsayılanlar sağlayan bir dosyadan ayarlandıktan SONRA en az ve kısa dosyaları içeren
mükemmel django-environ'dan oluşur . Bu bize etkili bir şekilde ayar enjeksiyonunu verir.ini
os.environment
settings/<purpose>.py
import settings/base.py
os.environment
INI
Buradaki hile, os.environment
içe aktarmadan önce değişiklik yapmaktır settings/base.py
.
Tam örneği görmek için şu repoya gidin: https://github.com/wooyek/django-settings-strategy
.
│ manage.py
├───data
└───website
├───settings
│ │ __init__.py <-- imports local for compatibility
│ │ base.py <-- almost all the settings, reads from proces environment
│ │ local.py <-- a few modifications for local development
│ │ production.py <-- ideally is empty 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
ayarlar / .env
Yerel kalkınma için varsayılanlar. Çoğunlukla gerekli ortam değişkenlerini ayarlamak için gizli bir dosya. Yerel geliştirme için gerekli değilse, bunları boş değerlere ayarlayın. Burada varsayılanları sağlarız ve settings/base.py
ortamdan eksikse başka herhangi bir makinede başarısız olmaz .
ayarlar / local.py
Burada olan, ortamın yüklenip settings/.env
ardından ortak ayarların içe aktarılmasıdır settings/base.py
. Bundan sonra yerel kalkınmayı kolaylaştırmak için birkaçını geçersiz kılabiliriz.
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
ayarlar / production.py
Üretim için bir ortam dosyası beklememeliyiz, ancak bir şeyi test edersek bir dosyaya sahip olmak daha kolaydır. Ama neyse, satır içi birkaç varsayılan sağlamak, bu yüzden settings/base.py
buna göre cevap verebilir.
environ.Env.read_env(Path(__file__) / "production.env", DEBUG='False', ASSETS_DEBUG='False')
from .base import *
Buradaki temel ilgi alanı DEBUG
ve ASSETS_DEBUG
geçersiz kılmalar, os.environ
SADECE ortamdan ve dosyadan EKSİKSİZLER ise python'a uygulanacaktır .
Bunlar üretim varsayılanlarımız olacak, onları ortama veya dosyaya koymaya gerek yok, ancak gerekirse geçersiz kılınabilir. Temiz!
ayarları / base.py
Bunlar çoğunlukla vanilya django ayarlarınızdır, birkaç koşul ve onları ortamdan okumaları çoktur. Neredeyse her şey burada, amaçlanan tüm ortamları tutarlı ve mümkün olduğunca benzer tutar.
Temel farklılıklar aşağıdadır (umarım bunlar açıklayıcıdır):
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',)
Son bit, burada gücü gösterir. ASSETS_DEBUG
mantıklı bir varsayılana sahiptir, bu settings/production.py
ayar geçersiz kılınabilir ve hatta bir ortam ayarı tarafından geçersiz kılınabilir! Yaşasın!
Aslında karışık bir hiyerarşimiz var:
- settings / .py - amaca göre varsayılanları ayarlar, sır saklamaz
- settings / base.py - çoğunlukla çevre tarafından kontrol edilir
- işlem ortamı ayarları - 12 faktör bebek!
- settings / .env - kolay başlatma için yerel varsayılanlar