TL: DR: เคล็ดลับคือการปรับเปลี่ยนos.environment
ก่อนที่คุณจะนำเข้าsettings/base.py
สิ่งsettings/<purpose>.py
นี้จะทำให้สิ่งต่างๆง่ายขึ้น
แค่คิดถึงไฟล์ที่เกี่ยวพันทั้งหมดนี้ทำให้ฉันปวดหัว การรวมการนำเข้า (บางครั้งมีเงื่อนไข) การเอาชนะการแก้ไขสิ่งที่ตั้งไว้แล้วในกรณีDEBUG
การตั้งค่าจะเปลี่ยนไปในภายหลัง ช่างเป็นฝันร้าย!
ตลอดหลายปีที่ผ่านมาฉันได้แก้ปัญหาต่าง ๆ ทั้งหมด พวกเขาทั้งหมดค่อนข้างทำงาน แต่มีความเจ็บปวดในการจัดการ WTF! เราต้องการความยุ่งยากทั้งหมดหรือไม่? เราเริ่มด้วยsettings.py
ไฟล์เดียว ตอนนี้เราต้องการเอกสารเพื่อรวมสิ่งเหล่านี้เข้าด้วยกันในลำดับที่ถูกต้อง!
ฉันหวังว่าในที่สุดฉันก็มาถึงจุดที่น่าพอใจ (ของฉัน) ด้วยวิธีแก้ปัญหาด้านล่าง
มาสรุปเป้าหมายกัน (บางคนธรรมดาบางคนเป็นของฉัน)
เก็บความลับเป็นความลับ - อย่าเก็บไว้ใน repo!
ตั้ง / คีย์อ่านและความลับผ่านการตั้งค่าสภาพแวดล้อมสไตล์ 12 ปัจจัย
มีค่าเริ่มต้นทางเลือกที่สมเหตุสมผล ทำเลดีเยี่ยมสำหรับการพัฒนาท้องถิ่นคุณไม่ต้องการอะไรมากไปกว่าค่าเริ่มต้น
… แต่พยายามรักษาค่าเริ่มต้นให้ปลอดภัย มันจะดีกว่าที่จะพลาดการตั้งค่าแทนที่ในท้องถิ่นกว่าต้องจำไว้เพื่อปรับการตั้งค่าเริ่มต้นที่ปลอดภัยสำหรับการผลิต
มีความสามารถในการเปิดDEBUG
/ ปิดในลักษณะที่อาจมีผลต่อการตั้งค่าอื่น ๆ (เช่นการใช้จาวาสคริปต์ที่บีบอัดหรือไม่)
การสลับไปมาระหว่างการตั้งค่าวัตถุประสงค์เช่นในท้องถิ่น / การทดสอบ / การจัดเตรียม / การผลิตควรขึ้นอยู่กับDJANGO_SETTINGS_MODULE
ไม่มีอะไรเพิ่มเติม
... แต่อนุญาตให้ parameterization DATABASE_URL
เพิ่มเติมผ่านการตั้งค่าสภาพแวดล้อมเช่น
... ยังอนุญาตให้พวกเขาใช้การตั้งค่าวัตถุประสงค์ที่แตกต่างกันและเรียกใช้พวกเขาในพื้นที่เคียงข้างกันเช่น การตั้งค่าการผลิตบนเครื่องนักพัฒนาท้องถิ่นเพื่อเข้าถึงฐานข้อมูลการผลิตหรือสไตล์การบีบอัดการทดสอบควัน
ล้มเหลวหากไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมอย่างชัดเจน (ต้องมีค่าว่างอย่างน้อยที่สุด) โดยเฉพาะอย่างยิ่งในการผลิตเช่น EMAIL_HOST_PASSWORD
.
ตอบสนองต่อการDJANGO_SETTINGS_MODULE
ตั้งค่าเริ่มต้นใน Manage.py ในระหว่างโครงการdjango-admin startproject
ให้เงื่อนไขให้น้อยที่สุดถ้าเงื่อนไขเป็นประเภทสภาพแวดล้อมวัตถุประสงค์ (เช่น. สำหรับแฟ้มบันทึกการตั้งค่าการผลิตและการหมุนของมัน) การตั้งค่าการแทนที่ในการเชื่อมโยงการตั้งค่าไฟล์วัตถุประสงค์
ทำไม่ได้
อย่าปล่อยให้ django อ่าน DJANGO_SETTINGS_MODULE ตั้งค่าไฟล์
ฮึ คิดว่าเมตาดาต้านี้เป็นอย่างไร หากคุณจำเป็นต้องมีไฟล์ (เช่น docker env) ให้อ่านไฟล์นั้นในสภาพแวดล้อมก่อนที่จะจ้องมองกระบวนการ django
อย่าแทนที่ DJANGO_SETTINGS_MODULE ในรหัสโครงการ / แอปของคุณเช่น ตามชื่อโฮสต์หรือชื่อกระบวนการ
หากคุณขี้เกียจที่จะตั้งค่าตัวแปรสภาพแวดล้อม (เช่นเดียวกับsetup.py test
) ให้ทำในการสร้างเครื่องมือก่อนที่คุณจะเรียกใช้รหัสโครงการ
หลีกเลี่ยงเวทย์มนตร์และการแพตช์วิธีที่ django อ่านการตั้งค่าของมันประมวลผลการตั้งค่าล่วงหน้า แต่ไม่รบกวนหลังจากนั้น
ไม่มีเรื่องไร้สาระตามตรรกะที่ซับซ้อน การกำหนดค่าควรได้รับการแก้ไขและไม่สามารถคำนวณได้ทันที การให้ค่าเริ่มต้นทางเลือกเป็นเพียงตรรกะเพียงพอที่นี่
คุณต้องการตรวจแก้จุดบกพร่องจริงๆหรือไม่ทำไมภายในเครื่องคุณถึงมีชุดการตั้งค่าที่ถูกต้อง แต่ในการผลิตบนเซิร์ฟเวอร์ระยะไกลบนเครื่องหนึ่งร้อยเครื่องสิ่งที่คำนวณต่างกัน? Oh! การทดสอบหน่วย? สำหรับการตั้งค่า? อย่างจริงจัง?
สารละลาย
กลยุทธ์ของฉันประกอบด้วยdjango-environ ที่ยอดเยี่ยมซึ่งใช้กับini
ไฟล์สไตล์ซึ่งเป็นos.environment
ค่าเริ่มต้นสำหรับการพัฒนาในท้องถิ่นsettings/<purpose>.py
ไฟล์บางไฟล์ที่สั้นและสั้นที่สุดที่มีการ
ตั้งค่าimport settings/base.py
หลังจากที่os.environment
ถูกตั้งค่าจากINI
ไฟล์ สิ่งนี้ให้การตั้งค่าการฉีดที่มีประสิทธิภาพ
เคล็ดลับที่นี่คือการปรับเปลี่ยนก่อนที่จะนำเข้าos.environment
settings/base.py
หากต้องการดูตัวอย่างทั้งหมดให้ไปที่ repo: 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
การตั้งค่า / .env
ค่าเริ่มต้นสำหรับการพัฒนาท้องถิ่น ไฟล์ลับเพื่อตั้งค่าตัวแปรสภาพแวดล้อมที่ต้องการเป็นส่วนใหญ่ ตั้งค่าเป็นค่าว่างหากไม่ต้องการในการพัฒนาท้องถิ่น เราให้บริการค่าเริ่มต้นที่นี่และไม่ได้อยู่ในsettings/base.py
จะไม่ล้มเหลวในเครื่องอื่น ๆ หากขาดหายไปจากสภาพแวดล้อม
การตั้งค่า / local.py
สิ่งที่เกิดขึ้นในที่นี่คือสภาพแวดล้อมในการโหลดจากนั้นนำเข้าจากตั้งค่าทั่วไปsettings/.env
settings/base.py
หลังจากนั้นเราสามารถแทนที่บางอย่างเพื่อความสะดวกในการพัฒนาท้องถิ่น
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
การตั้งค่า / production.py
สำหรับการผลิตเราไม่ควรคาดหวังไฟล์สภาพแวดล้อม แต่จะมีไฟล์ได้ง่ายกว่าถ้าเรากำลังทดสอบบางอย่าง แต่อย่างไรก็ตามเกรงว่าจะมีค่าเริ่มต้นไม่กี่อินไลน์ดังนั้นsettings/base.py
สามารถตอบสนองได้
environ.Env.read_env(Path(__file__) / "production.env", DEBUG='False', ASSETS_DEBUG='False')
from .base import *
จุดสำคัญที่น่าสนใจที่นี่คือDEBUG
และASSETS_DEBUG
แทนที่พวกเขาจะถูกนำไปใช้กับหลามos.environ
เท่านั้นหากพวกเขากำลังพลาดจากสภาพแวดล้อมและไฟล์
สิ่งเหล่านี้จะเป็นค่าเริ่มต้นการผลิตของเราไม่จำเป็นต้องใส่ไว้ในสภาพแวดล้อมหรือไฟล์ แต่สามารถแทนที่ได้หากจำเป็น เรียบร้อย!
การตั้งค่า / base.py
นี่คือการตั้งค่า vanango django ของคุณเป็นส่วนใหญ่โดยมีเงื่อนไขเล็กน้อยและมีจำนวนมากที่อ่านจากสภาพแวดล้อม เกือบทุกอย่างอยู่ที่นี่ทำให้สภาพแวดล้อมทั้งหมดสอดคล้องกันและใกล้เคียงที่สุด
ความแตกต่างที่สำคัญอยู่ด้านล่าง (ฉันหวังว่าสิ่งเหล่านี้อธิบายด้วยตนเอง):
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',)
บิตสุดท้ายแสดงพลังที่นี่ ASSETS_DEBUG
มีค่าเริ่มต้นที่สมเหตุสมผลซึ่งสามารถแทนที่ได้settings/production.py
และแม้กระทั่งสิ่งที่สามารถแทนที่ได้ด้วยการตั้งค่าสภาพแวดล้อม! เย้!
ผลที่ตามมาเรามีลำดับความสำคัญแบบผสม:
- settings / .py - ตั้งค่าเริ่มต้นตามวัตถุประสงค์ไม่เก็บความลับ
- settings / base.py - ส่วนใหญ่ควบคุมโดยสภาพแวดล้อม
- การตั้งค่าสภาพแวดล้อมกระบวนการ - 12 ปัจจัยที่รัก!
- settings / .env - ค่าเริ่มต้นในเครื่องสำหรับการเริ่มต้นระบบที่ง่ายดาย