วิธีจัดการการตั้งค่า vs การผลิตในท้องถิ่นใน Django


298

วิธีที่แนะนำในการจัดการการตั้งค่าสำหรับการพัฒนาท้องถิ่นและเซิร์ฟเวอร์การผลิตคืออะไร? บางส่วนของพวกเขา (เช่นค่าคงที่และอื่น ๆ ) สามารถเปลี่ยนแปลง / เข้าถึงได้ในทั้งคู่ แต่บางส่วนของพวกเขา (เช่นพา ธ ไปยังไฟล์คงที่) จำเป็นต้องคงที่แตกต่างกันดังนั้นจึงไม่ควรเขียนทับทุกครั้งที่มีการปรับใช้รหัสใหม่

settings.pyปัจจุบันผมเพิ่มค่าคงที่ทั้งหมดเพื่อ แต่ทุกครั้งที่ฉันเปลี่ยนค่าคงที่แบบโลคอลฉันต้องคัดลอกไปยังเซิร์ฟเวอร์ที่ใช้งานจริงและแก้ไขไฟล์สำหรับการเปลี่ยนแปลงเฉพาะที่ใช้ในการผลิต ... :(

แก้ไข: ดูเหมือนว่าไม่มีคำตอบมาตรฐานสำหรับคำถามนี้ฉันยอมรับวิธีที่นิยมที่สุด



กรุณาดูได้ที่Django-การกำหนดค่า
JJD

2
วิธีการที่ได้รับการยอมรับไม่ใช่วิธีที่นิยมมากที่สุดอีกต่อไป
แดเนียล

2
django-split-settingsใช้งานง่ายมาก มันไม่จำเป็นต้องเขียนการตั้งค่าเริ่มต้นใด ๆ
sobolevn

คุณควรใช้ไฟล์ base.py และใน local.py ของคุณ "จาก. base import *", เดียวกันใน production.py "จาก. base import *" คุณต้องเปิดใช้งานโครงการด้วย: python Manage.py runserver - settings = project_name.settings.local
Roberth Solís

คำตอบ:


127

ในsettings.py:

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

คุณสามารถแทนที่สิ่งที่จำเป็นในlocal_settings.py; ควรอยู่นอกเหนือการควบคุมเวอร์ชันของคุณแล้ว แต่เนื่องจากคุณพูดถึงการคัดลอกฉันเดาว่าคุณจะไม่ใช้;)


3
เพื่อความสะดวกในการติดตาม / ปรับใช้การตั้งค่าใหม่ให้ใช้ "local_settings.py" บนเครื่องผลิต / ทดสอบและไม่มีการพัฒนา
John Mee

8
นั่นคือวิธีที่ฉันทำ - เพิ่มบรรทัดเหล่านั้นที่ส่วนท้ายของ settings.py เพื่อให้พวกเขาสามารถแทนที่การตั้งค่าเริ่มต้นได้
daonb

61
วิธีการนี้หมายความว่าคุณมีรหัสที่ไม่มีเวอร์ชันที่ใช้ในการพัฒนาและการผลิต และนักพัฒนาซอฟต์แวร์ทุกคนมีรหัสฐานที่แตกต่างกันฉันเรียกว่า anti-pattern ที่นี่
pydanny

8
@pydanny ปัญหาคือว่า Django เก็บมันเป็นค่าที่ตั้งไว้ในไฟล์. py คุณไม่สามารถคาดหวังได้ว่าผู้พัฒนาและเซิร์ฟเวอร์ที่ใช้งานจริงทั้งหมดจะใช้การตั้งค่าเดียวกันดังนั้นคุณต้องแก้ไขไฟล์. py นี้หรือใช้โซลูชันอื่น (ไฟล์. ini, สภาพแวดล้อม ฯลฯ )
Tupteq

3
ฉันชอบโทรหาโมดูลsettings_localตรงข้ามlocal_settingsกับจัดกลุ่มด้วยsettings.pyรายชื่อโฟลเดอร์ตามตัวอักษร ให้settings_local.pyออกจากการควบคุมรุ่นใช้.gitignoreเป็นข้อมูลประจำตัวที่ไม่ได้อยู่ใน Git ลองจินตนาการถึงการเปิดแหล่งที่มาโดยบังเอิญ ฉันเก็บไฟล์เทมเพลตไว้ในคอมไพล์แล้วsettings_local.py.txtแทน
ตัวแบ่งบรรทัด

297

สอง Scoops ของ Django: แนวทางปฏิบัติที่ดีที่สุดสำหรับ Django 1.5แนะนำให้ใช้การควบคุมเวอร์ชันสำหรับไฟล์การตั้งค่าของคุณและจัดเก็บไฟล์ในไดเรกทอรีแยก:

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

base.pyไฟล์มีการตั้งค่าทั่วไป (เช่น MEDIA_ROOT หรือ ADMIN) ในขณะที่local.pyและproduction.pyมีการตั้งค่าเว็บไซต์ที่เฉพาะเจาะจง:

ในไฟล์ฐานsettings/base.py:

INSTALLED_APPS = (
    # common apps...
)

ในไฟล์การตั้งค่าการพัฒนาท้องถิ่นsettings/local.py:

from project.settings.base import *

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

ในไฟล์การตั้งค่าการผลิตไฟล์settings/production.py:

from project.settings.base import *

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

จากนั้นเมื่อคุณรัน django คุณจะเพิ่ม--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

ผู้เขียนหนังสือได้วางเทมเพลตโครงร่างตัวอย่างโครงการบน Github


62
โปรดทราบว่าแทนที่จะใช้--settingsทุกครั้งคุณสามารถตั้งค่าDJANGO_SETTINGS_MODULEenvvar สิ่งนี้ใช้ได้ดีกับ Heroku: ตั้งค่าแบบโกลบอลเป็นแบบใช้งานจริงแล้วแทนที่ด้วย dev ในไฟล์. env ของคุณ
Simon Weber

9
ใช้DJANGO_SETTINGS_MODULEenv var เป็นความคิดที่ดีที่สุดที่นี่ขอบคุณ Simon
kibibu

20
คุณอาจต้องเปลี่ยนBASE_DIRการตั้งค่าเป็นos.path.dirname(os.path.realpath(os.path.dirname(__file__) + "/.."))
Petr Peller

5
@rsp ตาม django docs คุณนำเข้าfrom django.conf import settingsซึ่งเป็นวัตถุที่ทำให้อินเทอร์เฟซเป็นนามธรรมและแยกรหัสออกจากตำแหน่งของการตั้งค่าdocs.djangoproject.com/th/dev/topics/settings/ …

3
หากฉันตั้งค่า DJANGO_SETTINGS_MODULE ผ่านตัวแปรสภาพแวดล้อมฉันยังต้องใช้ os.environ.setdefault ("DJANGO_SETTINGS_MODULE", "projectname.settings.production") ในไฟล์ wsgi.py ของฉันหรือไม่ นอกจากนี้ฉันได้ตั้งค่า var สิ่งแวดล้อมโดยใช้: ส่งออก DJANGO_SETTINGS_MODULE = projectname.settings.local แต่เมื่อฉันปิดปิดเทอร์มินัลจะหายไป ฉันจะทำอย่างไรเพื่อให้มั่นใจว่าได้รับการบันทึก ฉันควรเพิ่มบรรทัดนั้นในไฟล์ bashrc หรือไม่
Kritz

71

แทนที่จะsettings.pyใช้โครงร่างนี้:

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

common.py เป็นที่ที่โครงร่างส่วนใหญ่ของคุณมีชีวิต

prod.py นำเข้าทุกอย่างจากสิ่งที่พบโดยทั่วไปและแทนที่สิ่งที่มันต้องการแทนที่:

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

# Production overrides
DEBUG = False
#...

ในทำนองเดียวกันdev.pyนำเข้าทุกอย่างจากcommon.pyและแทนที่สิ่งที่มันต้องการที่จะแทนที่

ท้ายที่สุด__init__.pyคือที่คุณตัดสินใจว่าจะโหลดการตั้งค่าใดและเป็นที่เก็บความลับด้วยดังนั้นไฟล์นี้ไม่ควรเป็นเวอร์ชั่น:

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

สิ่งที่ฉันชอบเกี่ยวกับวิธีนี้คือ:

  1. ทุกอย่างอยู่ในระบบการกำหนดรุ่นของคุณยกเว้นความลับ
  2. การกำหนดค่าส่วนใหญ่อยู่ในที่เดียว: common.py .
  3. สิ่งที่เฉพาะเจาะจงในการผลิตเข้าไปในprod.pyสิ่งที่เฉพาะเจาะจงไปในdev.pyเฉพาะไปใน มันง่ายมาก
  4. คุณสามารถลบล้างสิ่งต่าง ๆ จากcommon.pyในprod.pyหรือdev.pyและคุณสามารถแทนที่สิ่งใดก็ได้ใน__init__.pyและคุณสามารถแทนที่อะไรใน
  5. เป็นงูหลามตรงไปตรงมา ไม่มีการนำเข้าแฮ็กอีกครั้ง

2
ฉันยังคงพยายามหาว่าจะตั้งค่าอะไรใน project.wsgi และไฟล์ Manage.py สำหรับไฟล์การตั้งค่า คุณจะทำให้แสงสว่างนี้ไหม โดยเฉพาะในไฟล์ Manage.py ฉันมีos.environ.setdefault("DJANGO_SETTINGS_MODULE", "foobar.settings")foobar เป็นโฟลเดอร์ที่มี__init__.pyไฟล์และการตั้งค่าคือโฟลเดอร์ที่มี__init__.pyไฟล์ที่มีความลับและนำเข้า dev.py ของฉันซึ่งนำเข้า common.py แก้ไขไม่เป็นไรฉันไม่ได้ติดตั้งโมดูลที่จำเป็น ความผิดฉันเอง! มันใช้งานได้ดี !!
teewuane

5
สองสิ่ง: 1) ดีกว่าในการตั้งค่า Debug = True ใน dev.py ของคุณแทนที่จะ = False ใน prod.py ของคุณ 2) แทนที่จะสลับในinit .py ให้สลับโดยใช้ DJANGO_SETTINGS_MODULE สภาพแวดล้อม var สิ่งนี้จะช่วยในการปรับใช้ PAAS (เช่น Heroku)
Rob Grant

เมื่อฉันใช้การตั้งค่านี้ใน django 1.8.4 และลอง runserver ฉันจะได้รับ "django.core.exceptions.ImproperlyConfigured: การตั้งค่า SECRET_KEY ต้องไม่ว่าง" แม้ฉันจะมี SECRET_KEY ในไฟล์initของฉัน ฉันพลาดอะไรไปรึเปล่า?
polarcare

การใช้งานบางอย่างเช่นAWS_SECRET_ACCESS_KEY = os.getenv ("AWS_SECRET_ACCESS_KEY")ปลอดภัยกว่าหรือไม่ คำถามที่ซื่อสัตย์ - ฉันรู้ว่าทำไมคุณไม่ต้องการให้เป็นเวอร์ชัน แต่ทางเลือกอื่นคือรับจากสภาพแวดล้อม คำถามใดที่ตั้งค่าตัวแปรสภาพแวดล้อมซึ่งแน่นอนว่าสามารถทิ้งไว้กับกลไกการปรับใช้ของคุณได้
JL Peyret

20

ฉันใช้การตั้งค่ารูปแบบ "if DEBUG" ที่แก้ไขเล็กน้อยซึ่ง Harper Shelby โพสต์ เห็นได้ชัดว่าขึ้นอยู่กับสภาพแวดล้อม (win / linux / ฯลฯ ) รหัสอาจต้องมีการปรับแต่งเล็กน้อย

ฉันเคยใช้ "ถ้า DEBUG" ก่อนหน้านี้ แต่ฉันพบว่าบางครั้งฉันต้องทำการทดสอบด้วย DEUBG ตั้งค่าเป็นเท็จ สิ่งที่ฉันต้องการแยกแยะว่าสภาพแวดล้อมเป็นการผลิตหรือการพัฒนาซึ่งทำให้ฉันมีอิสระในการเลือกระดับ DEBUG

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'

ฉันยังคงพิจารณาวิธีการตั้งค่าที่กำลังดำเนินการอยู่ ฉันไม่เคยเห็นวิธีจัดการการตั้งค่า Django ที่ครอบคลุมทุกฐานและในเวลาเดียวกันก็ไม่ได้ยุ่งยากในการติดตั้งทั้งหมด (ฉันไม่ได้ใช้วิธีการตั้งค่าไฟล์ 5x)


นี่คือสิ่งที่การตั้งค่าของ Django เป็นไฟล์รหัสจริงช่วยให้และฉันก็บอกใบ้ ฉันไม่ได้ทำอะไรแบบนี้ แต่มันเป็นวิธีแก้ปัญหาที่อาจเป็นคำตอบทั่วไปที่ดีกว่าของฉัน
Harper Shelby

3
ฉันเพิ่งพบปัญหานี้เป็นครั้งแรกและเลือกที่จะ (สำเร็จ!) ใช้โซลูชันของคุณแตกต่างกันเล็กน้อย: ฉันใช้ uuid.getnode () เพื่อค้นหา uuid ของระบบของฉัน ดังนั้นฉันกำลังทดสอบว่า uuid.getnode () == 12345678901 (จริง ๆ แล้วเป็นตัวเลขอื่น) แทนการทดสอบ os.environ ที่คุณใช้ ฉันไม่พบ documenation ที่จะโน้มน้าวฉันว่าระบบปฏิบัติการ ['COMPUTERNAME'] นั้นไม่เหมือนกันสำหรับคอมพิวเตอร์
Joe Golton

ระบบปฏิบัติการ ['COMPUTERNAME'] ไม่ทำงานบน Amazon AWS Ubuntu ฉันได้รับ KeyError
nu everest

เมื่อใช้ UUID โซลูชันนี้ได้พิสูจน์แล้วว่าดีที่สุดและง่ายที่สุดสำหรับฉัน ไม่จำเป็นต้องมีการเย็บปะติดปะต่อกันที่ซับซ้อนและมากเกินมาตรฐาน ในสภาพแวดล้อมการใช้งานจริงคุณยังต้องวางรหัสผ่านฐานข้อมูลและ SECRET_KEY ในไฟล์แยกต่างหากที่อยู่นอกการควบคุมเวอร์ชัน
nu everest

os.environ['COMPUTERNAME']น่าเสียดายที่ไม่สามารถใช้งาน PythonAnywhere ได้ คุณได้รับ KeyError
nbeuchat

14

ฉันใช้ settings_local.py และ settings_production.py หลังจากลองตัวเลือกหลายตัวฉันพบว่ามันง่ายที่จะเสียเวลากับการแก้ปัญหาที่ซับซ้อนเมื่อเพียงแค่มีสองไฟล์การตั้งค่าก็รู้สึกง่ายและรวดเร็ว

เมื่อคุณใช้ mod_python / mod_wsgi สำหรับโครงการ Django ของคุณคุณจะต้องชี้ไปที่ไฟล์การตั้งค่าของคุณ หากคุณชี้ไปที่ app / settings_local.py บนเซิร์ฟเวอร์ในพื้นที่ของคุณและ app / settings_production.py บนเซิร์ฟเวอร์ที่ใช้งานจริงชีวิตจะกลายเป็นเรื่องง่าย เพียงแก้ไขไฟล์การตั้งค่าที่เหมาะสมและรีสตาร์ทเซิร์ฟเวอร์ (เซิร์ฟเวอร์การพัฒนา Django จะรีสตาร์ทโดยอัตโนมัติ)


2
แล้วเซิร์ฟเวอร์การพัฒนาท้องถิ่นล่ะ? มีวิธีใดที่จะบอก django webserver (ใช้งานpython manage.py runserver) ไฟล์การตั้งค่าที่จะใช้?
akv

2
@akv หากคุณเพิ่ม --settings = [ชื่อโมดูล] (ไม่มีนามสกุล. py) ที่ส่วนท้ายของคำสั่ง runserver คุณสามารถระบุไฟล์การตั้งค่าที่จะใช้ หากคุณกำลังจะทำสิ่งนั้นทำสิ่งที่ชอบและทำเชลล์สคริปต์ / ไฟล์แบทช์ด้วยการตั้งค่าการพัฒนาที่กำหนดไว้ เชื่อใจฉันนิ้วของคุณจะขอบคุณ
T. Stone

นี่คือทางออกที่ฉันใช้ การแฮ็กไฟล์การตั้งค่าที่จะใช้สำหรับการผลิตหรือการพัฒนานั้นเป็นเรื่องที่ยุ่งเหยิง
George Godik

4
ฉันคิดว่ามันดีกว่าที่จะใช้ settings.py ในการพัฒนาเนื่องจากคุณไม่จำเป็นต้องระบุไว้ตลอดเวลา
Andre Bossard

ฉันถูกต้องในสมมติว่าวิธีนี้ต้องนำเข้าโมดูลการตั้งค่าผ่านทางพร็อกซี่ django.conf.settings? มิฉะนั้นคุณจะต้องแก้ไขการประกาศการนำเข้าเพื่อชี้ไปที่ไฟล์การตั้งค่าที่ถูกต้องเมื่อกดสด
Groady

8

TL: DR: เคล็ดลับคือการปรับเปลี่ยนos.environmentก่อนที่คุณจะนำเข้าsettings/base.pyสิ่งsettings/<purpose>.pyนี้จะทำให้สิ่งต่างๆง่ายขึ้น


แค่คิดถึงไฟล์ที่เกี่ยวพันทั้งหมดนี้ทำให้ฉันปวดหัว การรวมการนำเข้า (บางครั้งมีเงื่อนไข) การเอาชนะการแก้ไขสิ่งที่ตั้งไว้แล้วในกรณีDEBUGการตั้งค่าจะเปลี่ยนไปในภายหลัง ช่างเป็นฝันร้าย!

ตลอดหลายปีที่ผ่านมาฉันได้แก้ปัญหาต่าง ๆ ทั้งหมด พวกเขาทั้งหมดค่อนข้างทำงาน แต่มีความเจ็บปวดในการจัดการ WTF! เราต้องการความยุ่งยากทั้งหมดหรือไม่? เราเริ่มด้วยsettings.pyไฟล์เดียว ตอนนี้เราต้องการเอกสารเพื่อรวมสิ่งเหล่านี้เข้าด้วยกันในลำดับที่ถูกต้อง!

ฉันหวังว่าในที่สุดฉันก็มาถึงจุดที่น่าพอใจ (ของฉัน) ด้วยวิธีแก้ปัญหาด้านล่าง

มาสรุปเป้าหมายกัน (บางคนธรรมดาบางคนเป็นของฉัน)

  1. เก็บความลับเป็นความลับ - อย่าเก็บไว้ใน repo!

  2. ตั้ง / คีย์อ่านและความลับผ่านการตั้งค่าสภาพแวดล้อมสไตล์ 12 ปัจจัย

  3. มีค่าเริ่มต้นทางเลือกที่สมเหตุสมผล ทำเลดีเยี่ยมสำหรับการพัฒนาท้องถิ่นคุณไม่ต้องการอะไรมากไปกว่าค่าเริ่มต้น

  4. … แต่พยายามรักษาค่าเริ่มต้นให้ปลอดภัย มันจะดีกว่าที่จะพลาดการตั้งค่าแทนที่ในท้องถิ่นกว่าต้องจำไว้เพื่อปรับการตั้งค่าเริ่มต้นที่ปลอดภัยสำหรับการผลิต

  5. มีความสามารถในการเปิดDEBUG/ ปิดในลักษณะที่อาจมีผลต่อการตั้งค่าอื่น ๆ (เช่นการใช้จาวาสคริปต์ที่บีบอัดหรือไม่)

  6. การสลับไปมาระหว่างการตั้งค่าวัตถุประสงค์เช่นในท้องถิ่น / การทดสอบ / การจัดเตรียม / การผลิตควรขึ้นอยู่กับDJANGO_SETTINGS_MODULEไม่มีอะไรเพิ่มเติม

  7. ... แต่อนุญาตให้ parameterization DATABASE_URLเพิ่มเติมผ่านการตั้งค่าสภาพแวดล้อมเช่น

  8. ... ยังอนุญาตให้พวกเขาใช้การตั้งค่าวัตถุประสงค์ที่แตกต่างกันและเรียกใช้พวกเขาในพื้นที่เคียงข้างกันเช่น การตั้งค่าการผลิตบนเครื่องนักพัฒนาท้องถิ่นเพื่อเข้าถึงฐานข้อมูลการผลิตหรือสไตล์การบีบอัดการทดสอบควัน

  9. ล้มเหลวหากไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมอย่างชัดเจน (ต้องมีค่าว่างอย่างน้อยที่สุด) โดยเฉพาะอย่างยิ่งในการผลิตเช่น EMAIL_HOST_PASSWORD.

  10. ตอบสนองต่อการDJANGO_SETTINGS_MODULEตั้งค่าเริ่มต้นใน Manage.py ในระหว่างโครงการdjango-admin startproject

  11. ให้เงื่อนไขให้น้อยที่สุดถ้าเงื่อนไขเป็นประเภทสภาพแวดล้อมวัตถุประสงค์ (เช่น. สำหรับแฟ้มบันทึกการตั้งค่าการผลิตและการหมุนของมัน) การตั้งค่าการแทนที่ในการเชื่อมโยงการตั้งค่าไฟล์วัตถุประสงค์

ทำไม่ได้

  1. อย่าปล่อยให้ django อ่าน DJANGO_SETTINGS_MODULE ตั้งค่าไฟล์
    ฮึ คิดว่าเมตาดาต้านี้เป็นอย่างไร หากคุณจำเป็นต้องมีไฟล์ (เช่น docker env) ให้อ่านไฟล์นั้นในสภาพแวดล้อมก่อนที่จะจ้องมองกระบวนการ django

  2. อย่าแทนที่ DJANGO_SETTINGS_MODULE ในรหัสโครงการ / แอปของคุณเช่น ตามชื่อโฮสต์หรือชื่อกระบวนการ
    หากคุณขี้เกียจที่จะตั้งค่าตัวแปรสภาพแวดล้อม (เช่นเดียวกับsetup.py test) ให้ทำในการสร้างเครื่องมือก่อนที่คุณจะเรียกใช้รหัสโครงการ

  3. หลีกเลี่ยงเวทย์มนตร์และการแพตช์วิธีที่ django อ่านการตั้งค่าของมันประมวลผลการตั้งค่าล่วงหน้า แต่ไม่รบกวนหลังจากนั้น

  4. ไม่มีเรื่องไร้สาระตามตรรกะที่ซับซ้อน การกำหนดค่าควรได้รับการแก้ไขและไม่สามารถคำนวณได้ทันที การให้ค่าเริ่มต้นทางเลือกเป็นเพียงตรรกะเพียงพอที่นี่
    คุณต้องการตรวจแก้จุดบกพร่องจริงๆหรือไม่ทำไมภายในเครื่องคุณถึงมีชุดการตั้งค่าที่ถูกต้อง แต่ในการผลิตบนเซิร์ฟเวอร์ระยะไกลบนเครื่องหนึ่งร้อยเครื่องสิ่งที่คำนวณต่างกัน? Oh! การทดสอบหน่วย? สำหรับการตั้งค่า? อย่างจริงจัง?

สารละลาย

กลยุทธ์ของฉันประกอบด้วยdjango-environ ที่ยอดเยี่ยมซึ่งใช้กับiniไฟล์สไตล์ซึ่งเป็นos.environmentค่าเริ่มต้นสำหรับการพัฒนาในท้องถิ่นsettings/<purpose>.pyไฟล์บางไฟล์ที่สั้นและสั้นที่สุดที่มีการ ตั้งค่าimport settings/base.py หลังจากที่os.environmentถูกตั้งค่าจากINIไฟล์ สิ่งนี้ให้การตั้งค่าการฉีดที่มีประสิทธิภาพ

เคล็ดลับที่นี่คือการปรับเปลี่ยนก่อนที่จะนำเข้าos.environmentsettings/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และแม้กระทั่งสิ่งที่สามารถแทนที่ได้ด้วยการตั้งค่าสภาพแวดล้อม! เย้!

ผลที่ตามมาเรามีลำดับความสำคัญแบบผสม:

  1. settings / .py - ตั้งค่าเริ่มต้นตามวัตถุประสงค์ไม่เก็บความลับ
  2. settings / base.py - ส่วนใหญ่ควบคุมโดยสภาพแวดล้อม
  3. การตั้งค่าสภาพแวดล้อมกระบวนการ - 12 ปัจจัยที่รัก!
  4. settings / .env - ค่าเริ่มต้นในเครื่องสำหรับการเริ่มต้นระบบที่ง่ายดาย

สวัสดี Janusz ... ดังนั้นในไฟล์. env จะไปที่คีย์ API และรหัสรับรองความถูกต้องและรหัสผ่านทั้งหมดหรือไม่ เช่นเดียวกับ TWILLIO_API = "abc123"? หรือ TWILLIO_API = env ("TWILLIO_API") หรือไม่
dbinott

ใช่ แต่นี่เป็นเพียงทางเลือกสำหรับการตั้งค่าสภาพแวดล้อม ไฟล์นี้มีประโยชน์สำหรับการพัฒนา แต่ไม่ได้บันทึกใน repo หรือส่งไปยังการผลิตซึ่งคุณควรใช้การตั้งค่าสภาพแวดล้อมอย่างเคร่งครัดหรือเทียบเท่าแพลตฟอร์มของคุณซึ่งจะเป็นการตั้งค่าสภาพแวดล้อมการตั้งค่าสำหรับกระบวนการเซิร์ฟเวอร์
Janusz Skonieczny

7

ฉันจัดการการกำหนดค่าของฉันด้วยความช่วยเหลือของDjango แยกการตั้งค่า

เป็นการแทนที่แบบหล่นสำหรับการตั้งค่าเริ่มต้น มันง่าย แต่สามารถกำหนดค่าได้ และไม่จำเป็นต้องทำการตั้งค่า exisitng ใหม่อีกครั้ง

นี่คือตัวอย่างเล็ก ๆ (ไฟล์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()
    )

แค่นั้นแหละ.

ปรับปรุง

ผมเขียนบล็อกโพสต์เกี่ยวกับการจัดการdjangoการตั้งค่า 's django-split-sttingsพร้อมด้วย มาดูกัน!


1
ฉันพยายามที่ .. วิ่งเข้าไปในกำแพงเมื่อฉันพยายามเรียกใช้การทดสอบหน่วย django ของฉัน .. ฉันไม่สามารถคิดออกว่าจะระบุไฟล์การตั้งค่าที่จะอ่านจาก
ไหน

ฉันได้สร้างส่วนสำคัญสำหรับคุณ: gist.github.com/sobolevn/006c734f0520439a4b6c16891d65406c
sobolevn

ฉันได้อะไรแบบนี้ในรหัสของฉันดังนั้นฉันตรวจสอบค่าสถานะ settings.DEBUG เพื่อทราบว่าฉันต้องการนำเข้าสิ่งต่าง ๆ หรือไม่ .. ค่าสถานะนั้นถูกตั้งค่าเป็นเท็จในการทดสอบหน่วย django (ดูที่นี่ ) ดังนั้นการทำงานของฉันคือ การทดสอบแต่ละครั้งเป็นเช่นนั้น
abbood

นี่คือคำถามอื่น: uwsgi.iniไฟล์ของฉันมีการตั้งค่าที่แตกต่างกันทั่ว dev / prod .. ความคิดใดวิธีที่จะทำให้มันเลือกค่าจากไฟล์การตั้งค่าของฉันได้อย่างไร
abbood

ขออภัยฉันไม่ได้รับการตั้งค่า คุณสามารถถามคำถามแยกต่างหากพร้อมรายละเอียดเพิ่มเติมและฉันจะพยายามช่วยคุณ
sobolevn

6

ปัญหาของการแก้ปัญหาเหล่านี้ส่วนใหญ่คือคุณอาจต้องใช้การตั้งค่าท้องถิ่นของคุณก่อนการตั้งค่าทั่วไปหรือหลังจากนั้นนั้น

ดังนั้นจึงเป็นไปไม่ได้ที่จะแทนที่สิ่งต่าง ๆ เช่น

  • การตั้งค่าเฉพาะ env กำหนดที่อยู่สำหรับพูล memcached และในไฟล์การตั้งค่าหลักค่านี้จะใช้เพื่อกำหนดค่าแบ็กเอนด์แคช
  • การตั้งค่าเฉพาะ env เพิ่มหรือลบแอพ / มิดเดิลแวร์ให้เป็นค่าเริ่มต้น

ในเวลาเดียวกัน.

วิธีแก้ปัญหาหนึ่งสามารถนำมาใช้โดยใช้ไฟล์การกำหนดค่า "ini" -style รองรับไฟล์หลายไฟล์การแก้ไขสตริงที่ขี้เกียจค่าเริ่มต้นและสินค้าอื่น ๆ มากมาย เมื่อมีการโหลดไฟล์จำนวนมากไฟล์จะสามารถโหลดได้มากขึ้นและค่าของมันจะแทนที่ไฟล์ก่อนหน้าหากมี

คุณโหลดไฟล์ config อย่างน้อยหนึ่งไฟล์ขึ้นอยู่กับที่อยู่ของเครื่องตัวแปรสภาพแวดล้อมและแม้กระทั่งค่าในไฟล์กำหนดค่าที่โหลดไว้ก่อนหน้านี้ จากนั้นคุณเพียงใช้ค่าการแยกวิเคราะห์เพื่อเติมการตั้งค่า

หนึ่งในกลยุทธ์ที่ฉันใช้ประสบความสำเร็จคือ:

  • โหลดdefaults.iniไฟล์เริ่มต้น
  • ตรวจสอบชื่อเครื่องและโหลดไฟล์ทั้งหมดที่ตรงกับ FQDN ย้อนกลับจากการจับคู่ที่สั้นที่สุดไปยังการจับคู่ที่ยาวที่สุด (ดังนั้นฉันโหลดnet.iniแล้วnet.domain.iniจากนั้นnet.domain.webserver01.iniแต่ละคนอาจเอาชนะค่าก่อนหน้านี้) บัญชีนี้สำหรับเครื่องของนักพัฒนาด้วยดังนั้นแต่ละบัญชีสามารถตั้งค่าไดรเวอร์ฐานข้อมูลที่ต้องการเป็นต้นเพื่อการพัฒนาในท้องถิ่น
  • ตรวจสอบว่ามี "ชื่อคลัสเตอร์" ประกาศหรือไม่และในกรณีที่โหลดcluster.cluster_name.iniซึ่งสามารถกำหนดสิ่งต่าง ๆ เช่นฐานข้อมูลและแคช IP

เป็นตัวอย่างของสิ่งที่คุณสามารถทำได้ด้วยสิ่งนี้คุณสามารถกำหนดค่า "โดเมนย่อย" ต่อหนึ่ง env ซึ่งจะใช้ในการตั้งค่าเริ่มต้น (เป็นhostname: %(subdomain).whatever.net) เพื่อกำหนดชื่อโฮสต์และคุกกี้ที่จำเป็นทั้งหมด django จำเป็นต้องทำงาน

นี่เป็น DRY ที่ฉันจะได้รับไฟล์ส่วนใหญ่ (ปัจจุบัน) มีเพียง 3 หรือ 4 การตั้งค่า นอกเหนือจากนี้ฉันต้องจัดการการกำหนดค่าลูกค้าดังนั้นจึงมีไฟล์การกำหนดค่าเพิ่มเติมอีกชุดหนึ่ง (เช่นชื่อฐานข้อมูลผู้ใช้และรหัสผ่านโดเมนย่อยที่กำหนดเป็นต้น) มีอยู่หนึ่งหรือมากกว่าหนึ่งต่อลูกค้า

คุณสามารถปรับขนาดนี้ให้ต่ำหรือสูงเท่าที่จำเป็นคุณเพียงแค่ใส่ไฟล์คีย์ที่คุณต้องการกำหนดค่าสำหรับแต่ละสภาพแวดล้อมและเมื่อจำเป็นต้องมีการกำหนดค่าใหม่ให้ใส่ค่าก่อนหน้าในการกำหนดค่าเริ่มต้นและแทนที่มัน ในกรณีที่จำเป็น.

ระบบนี้ได้รับการพิสูจน์แล้วว่าเชื่อถือได้และทำงานได้ดีกับการควบคุมเวอร์ชัน มันถูกใช้เป็นเวลานานในการจัดการสองกลุ่มแยกของแอปพลิเคชัน (15 หรือมากกว่ากรณีของเว็บไซต์ django ต่อเครื่อง), กับลูกค้ามากกว่า 50, กลุ่มที่มีการเปลี่ยนแปลงขนาดและสมาชิกขึ้นอยู่กับอารมณ์ของระบบ .. .


1
คุณมีตัวอย่างของวิธีโหลดการตั้งค่าจาก ini ไปยังการตั้งค่าของ Django หรือไม่?
kaleissin

ดูdocs.python.org/2/library/configparser.html คุณสามารถโหลด parser ด้วยconfig = ConfigParser.ConfigParser() แล้วอ่านไฟล์ของคุณและได้รับค่าใช้config.read(array_of_filenames) config.get(section, option)ดังนั้นก่อนอื่นคุณโหลดการกำหนดค่าของคุณจากนั้นคุณใช้มันเพื่ออ่านค่าสำหรับการตั้งค่า
เขียนใหม่

5

ฉันยังทำงานกับ Laravel และฉันชอบการนำไปใช้ที่นั่น ฉันพยายามเลียนแบบและรวมเข้ากับโซลูชันที่เสนอโดย T. Stone (ดูด้านบน):

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

บางทีสิ่งนี้จะช่วยให้คุณ


4

จำไว้ว่า settings.py เป็นไฟล์รหัสสด สมมติว่าคุณไม่ได้ตั้งค่า DEBUG ในการผลิต (ซึ่งเป็นแนวปฏิบัติที่ดีที่สุด) คุณสามารถทำสิ่งต่อไปนี้:

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

ค่อนข้างธรรมดา แต่ในทางทฤษฎีแล้วคุณสามารถขึ้นไปสู่ความซับซ้อนในระดับใดก็ได้ตามมูลค่าของ DEBUG หรือตัวแปรหรือการตรวจสอบโค้ดอื่น ๆ ที่คุณต้องการใช้


4

สำหรับโครงการส่วนใหญ่ของฉันฉันใช้รูปแบบต่อไปนี้:

  1. สร้าง settings_base.py ที่ฉันเก็บการตั้งค่าที่ใช้กันทั่วไปในทุกสภาพแวดล้อม
  2. เมื่อใดก็ตามที่ฉันต้องการใช้สภาพแวดล้อมใหม่ที่มีข้อกำหนดเฉพาะฉันจะสร้างไฟล์การตั้งค่าใหม่ (เช่น settings_local.py) ซึ่งสืบทอดเนื้อหาของ settings_base.py และการแทนที่ / เพิ่มตัวแปรการตั้งค่าที่เหมาะสม ( from settings_base import *)

(ในการทำงาน manage.py กับการตั้งค่าที่กำหนดเองไฟล์ที่คุณเพียงแค่ใช้ตัวเลือกคำสั่ง --settings: manage.py <command> --settings=settings_you_wish_to_use.py)


3

โซลูชันของฉันสำหรับปัญหาดังกล่าวยังเป็นส่วนผสมของโซลูชันบางอย่างที่ระบุไว้แล้วที่นี่:

  • ฉันเก็บไฟล์local_settings.pyที่มีเนื้อหาUSING_LOCAL = Trueใน dev และUSING_LOCAL = Falseprod
  • ในsettings.pyฉันจะนำเข้าไฟล์นั้นเพื่อรับการUSING_LOCALตั้งค่า

จากนั้นฉันจะยึดการตั้งค่าที่ขึ้นกับสภาพแวดล้อมทั้งหมดของฉัน:

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

ฉันชอบที่จะมีไฟล์ settings.py แยกกันสองไฟล์ที่ฉันต้องบำรุงรักษาเพราะฉันสามารถทำให้โครงสร้างการตั้งค่าของฉันเป็นไฟล์เดียวได้ง่ายกว่าการกระจายไปยังหลาย ๆ ไฟล์ เช่นนี้เมื่อฉันอัปเดตการตั้งค่าฉันไม่ลืมที่จะทำสำหรับทั้งสองสภาพแวดล้อม

แน่นอนว่าทุกวิธีมีข้อเสียและวิธีนี้ก็ไม่มีข้อยกเว้น ปัญหาที่นี่คือฉันไม่สามารถเขียนทับlocal_settings.pyไฟล์เมื่อใดก็ตามที่ฉันผลักดันการเปลี่ยนแปลงของฉันในการผลิตหมายถึงฉันไม่สามารถคัดลอกไฟล์ทั้งหมดสุ่มสี่สุ่มห้า แต่นั่นคือสิ่งที่ฉันสามารถอยู่ด้วย


3

ฉันใช้รูปแบบของสิ่งที่ jpartogi กล่าวไว้ข้างต้นฉันพบว่าสั้นกว่าเล็กน้อย:

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)

โดยทั่วไปในคอมพิวเตอร์แต่ละเครื่อง (การพัฒนาหรือการผลิต) ฉันมีไฟล์ hostname_settings.py ที่เหมาะสมซึ่งโหลดขึ้นแบบไดนามิก


3

นอกจากนี้ยังมีการตั้งค่า Django Classy ฉันเป็นแฟนตัวยงของมัน มันถูกสร้างขึ้นโดยหนึ่งในคนที่กระตือรือร้นที่สุดใน Django IRC คุณจะใช้สภาพแวดล้อม vars เพื่อกำหนดสิ่งต่าง ๆ

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


3

1 - สร้างโฟลเดอร์ใหม่ภายในแอปและการตั้งค่าชื่อของคุณ

2 - ตอนนี้สร้าง__init__.pyไฟล์ใหม่ในนั้นและภายในเขียน

from .base import *

try:
    from .local import *
except:
    pass

try:
    from .production import *
except:
    pass

3 - สร้างสามไฟล์ใหม่ในการตั้งค่าโฟลเดอร์ชื่อlocal.pyและproduction.pyและbase.pyและ

4 - ข้างในbase.pyคัดลอกเนื้อหาทั้งหมดของsettings.pyโฟลเดอร์ก่อนหน้าและเปลี่ยนชื่อด้วยสิ่งที่แตกต่างสมมติว่าold_settings.pyโฟลเดอร์และเปลี่ยนชื่อกับบางสิ่งบางอย่างที่แตกต่างกันให้พูดของ

5 - ใน base.py เปลี่ยนเส้นทาง BASE_DIR ของคุณเพื่อชี้ไปที่เส้นทางใหม่ของการตั้งค่า

เส้นทางเก่า -> BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

เส้นทางใหม่ -> BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

ด้วยวิธีนี้คุณสามารถจัดโครงสร้างโครงการและสามารถจัดการได้ระหว่างการผลิตและการพัฒนาท้องถิ่น


2

เพื่อที่จะใช้settingsการกำหนดค่าที่แตกต่างกันในสภาพแวดล้อมที่แตกต่างกันให้สร้างไฟล์การตั้งค่าที่แตกต่างกัน และในสคริปต์การปรับใช้เริ่มเซิร์ฟเวอร์โดยใช้--settings=<my-settings.py>พารามิเตอร์ซึ่งคุณสามารถใช้การตั้งค่าที่แตกต่างกันในสภาพแวดล้อมที่แตกต่างกัน

ประโยชน์ของการใช้วิธีนี้ :

  1. การตั้งค่าของคุณจะเป็นแบบแยกส่วนตามสภาพแวดล้อม

  2. คุณสามารถนำเข้าที่master_settings.pyมีการกำหนดค่าฐานในenvironmnet_configuration.pyและแทนที่ค่าที่คุณต้องการเปลี่ยนในสภาพแวดล้อมที่

  3. หากคุณมีทีมขนาดใหญ่นักพัฒนาแต่ละคนอาจมีของตัวเองlocal_settings.pyซึ่งพวกเขาสามารถเพิ่มลงในที่เก็บรหัสได้โดยไม่ต้องเสี่ยงกับการปรับเปลี่ยนการกำหนดค่าเซิร์ฟเวอร์ คุณสามารถเพิ่มการตั้งค่าท้องถิ่นเหล่านี้.gitnoreหากคุณใช้คอมไพล์หรือ.hginoreถ้าคุณใช้Mercurialสำหรับการควบคุมเวอร์ชัน (หรืออื่น ๆ ) วิธีนั้นการตั้งค่าในเครื่องจะไม่ได้เป็นส่วนหนึ่งของฐานรหัสจริงที่ทำให้มันสะอาด


2

ฉันแบ่งการตั้งค่าของฉันดังนี้

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

เรามี 3 สภาพแวดล้อม

  • dev
  • จัดฉาก
  • การผลิต

ตอนนี้การแสดงละครและการผลิตที่เห็นได้ชัดควรมีสภาพแวดล้อมที่คล้ายกันสูงสุด ดังนั้นเราเก็บprod.pyทั้งคู่ไว้

แต่มีกรณีที่ฉันต้องระบุเซิร์ฟเวอร์ที่ใช้งานอยู่เป็นเซิร์ฟเวอร์ที่ใช้งานจริง @T คำตอบของ Stone ช่วยให้ฉันเขียนเช็คดังนี้

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

ฉันแยกความแตกต่างใน Manage.py และสร้างไฟล์การตั้งค่าแยกกันสองไฟล์: local_settings.py และ prod_settings.py

ใน Manage.py ฉันจะตรวจสอบว่าเซิร์ฟเวอร์เป็นเซิร์ฟเวอร์ภายในหรือเซิร์ฟเวอร์ที่ใช้งานจริง หากเป็นเซิร์ฟเวอร์ภายในเครื่องก็จะโหลด local_settings.py และเป็นเซิร์ฟเวอร์ที่ใช้งานจริงมันจะโหลด prod_settings.py โดยทั่วไปนี่เป็นลักษณะที่:

#!/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)

ฉันพบว่าเป็นการง่ายกว่าที่จะแยกไฟล์การตั้งค่าออกเป็นสองไฟล์แยกกันแทนที่จะทำ ifs จำนวนมากภายในไฟล์การตั้งค่า


1

เพื่อเป็นทางเลือกในการดูแลรักษาไฟล์ที่แตกต่างหากคุณใช้: หากคุณใช้ git หรือ VCS อื่น ๆ เพื่อส่งรหัสจากโลคัลไปยังเซิร์ฟเวอร์สิ่งที่คุณสามารถทำได้คือเพิ่มไฟล์การตั้งค่าไปยัง. gitignore

สิ่งนี้จะช่วยให้คุณมีเนื้อหาที่แตกต่างกันในทั้งสองที่โดยไม่มีปัญหา ดังนั้นบนเซิร์ฟเวอร์คุณสามารถกำหนดค่า settings.py รุ่นที่เป็นอิสระและการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นบนโลคัลจะไม่สะท้อนบนเซิร์ฟเวอร์และในทางกลับกัน

นอกจากนี้มันจะลบไฟล์ settings.py จาก github เช่นกันซึ่งเป็นความผิดครั้งใหญ่ซึ่งฉันได้เห็นมือใหม่จำนวนมากกำลังทำอยู่



0

ฉันคิดว่าคำแนะนำที่ดีที่สุดคือ @T Stone แต่ฉันไม่รู้ว่าทำไมไม่ใช้ธง DEBUG ใน Django ฉันเขียนโค้ดด้านล่างสำหรับเว็บไซต์ของฉัน:

if DEBUG:
    from .local_settings import *

วิธีแก้ปัญหาอย่างง่ายเสมอดีกว่าวิธีแก้ปัญหาที่ซับซ้อน


-2

ฉันพบคำตอบที่นี่มีประโยชน์มาก (สิ่งนี้ได้รับการแก้ไขอย่างชัดเจนมากกว่านี้หรือไม่การตอบกลับครั้งสุดท้ายเมื่อหนึ่งปีที่แล้ว) หลังจากพิจารณาวิธีการทั้งหมดที่ระบุไว้ฉันพบวิธีแก้ปัญหาที่ฉันไม่เห็นในรายการที่นี่

เกณฑ์ของฉันคือ:

  • ทุกอย่างควรอยู่ในการควบคุมแหล่งที่มา ฉันไม่ชอบบิตเที่ยวยุ่งยิ่ง
  • เป็นการดีที่รักษาการตั้งค่าไว้ในไฟล์เดียว ฉันลืมสิ่งต่าง ๆ ถ้าฉันไม่ได้มองถูก :)
  • ไม่มีการแก้ไขด้วยตนเองเพื่อปรับใช้ ควรจะสามารถทดสอบ / push / ปรับใช้กับคำสั่งผ้าเดียว
  • หลีกเลี่ยงการรั่วไหลของการตั้งค่าการพัฒนาไปสู่การผลิต
  • ให้ใกล้เคียงที่สุดกับ "มาตรฐาน" (* ไอ *) รูปแบบ Django ให้มากที่สุด

ฉันคิดว่าการสลับบนเครื่องโฮสต์ทำให้รู้สึกบางอย่าง แต่แล้วคิดว่าปัญหาจริงที่นี่คือการตั้งค่าที่แตกต่างกันสำหรับสภาพแวดล้อมที่แตกต่างกันและมีช่วงเวลา aha ฉันวางรหัสนี้ไว้ท้ายไฟล์ settings.py:

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'

ด้วยวิธีนี้แอพจะใช้ค่าเริ่มต้นเป็นการตั้งค่าการผลิตซึ่งหมายความว่าคุณจะ "ยกเว้น" สภาพแวดล้อมการพัฒนาของคุณอย่างชัดเจน มันปลอดภัยกว่ามากหากลืมตั้งค่าตัวแปรสภาพแวดล้อมแบบโลคัลมากกว่าเป็นวิธีอื่นและคุณลืมที่จะตั้งค่าบางอย่างในการผลิตและอนุญาตให้ใช้การตั้งค่า dev บางอย่าง

เมื่อพัฒนาในพื้นที่จากเชลล์หรือใน. bash_profile หรือที่ใดก็ได้:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(หรือหากคุณกำลังพัฒนาบน Windows ให้ตั้งค่าผ่านทางแผงควบคุมหรือสิ่งที่เรียกว่าวันนี้ ... Windows ทำให้มันชัดเจนจนคุณสามารถตั้งค่าตัวแปรสภาพแวดล้อมได้)

ด้วยวิธีการนี้การตั้งค่า dev ทั้งหมดอยู่ในที่เดียว (มาตรฐาน) และเพียงแทนที่การผลิตตามที่ต้องการ การล้อเล่นด้วยการตั้งค่าการพัฒนาใด ๆ ควรจะปลอดภัยอย่างสมบูรณ์เพื่อกระทำการควบคุมแหล่งที่มาโดยไม่มีผลกระทบต่อการผลิต


ดีกว่าที่จะรักษาไฟล์กำหนดค่าที่แตกต่างกันและเลือกใช้ตัวแปร env มาตรฐาน DJango DJANGO_SETTINGS_MODULE
Rob Grant
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.