Làm cách nào để quản lý cài đặt cục bộ và sản xuất trong Django?


298

Cách xử lý các cài đặt được đề xuất cho phát triển cục bộ và máy chủ sản xuất là gì? Một số trong số chúng (như hằng số, v.v.) có thể được thay đổi / truy cập trong cả hai, nhưng một số trong số chúng (như đường dẫn đến tệp tĩnh) cần phải khác nhau và do đó không nên bị ghi đè mỗi khi mã mới được triển khai.

Hiện tại, tôi đang thêm tất cả các hằng số vào settings.py. Nhưng mỗi khi tôi thay đổi một số hằng số cục bộ, tôi phải sao chép nó vào máy chủ sản xuất và chỉnh sửa tệp để thay đổi cụ thể về sản xuất ... :(

Chỉnh sửa: có vẻ như không có câu trả lời chuẩn cho câu hỏi này, tôi đã chấp nhận phương pháp phổ biến nhất.



Xin hãy xem cấu hình django .
JJD

2
Phương pháp được chấp nhận không còn là phương pháp phổ biến nhất.
Daniel

2
django-split-settings rất dễ sử dụng. Nó không yêu cầu viết lại bất kỳ cài đặt mặc định.
sobolevn

bạn nên sử dụng tệp base.txt và trong local.txt của bạn "từ .base import *", giống như trong sản phẩm của bạn " settings = project_name.sinstall.local
Roberth Solís

Câu trả lời:


127

Trong settings.py:

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

Bạn có thể ghi đè những gì cần thiết trong local_settings.py; nó sẽ nằm ngoài tầm kiểm soát phiên bản của bạn. Nhưng vì bạn đề cập đến việc sao chép nên tôi đoán bạn không sử dụng;)


3
Để dễ dàng theo dõi / triển khai các cài đặt mới, hãy sử dụng "local_sinstall.py" trên các máy sản xuất / thử nghiệm và không có gì trong quá trình phát triển.
John Mee

8
Đó là cách tôi làm - thêm các dòng đó vào cuối settings.txt để chúng có thể ghi đè cài đặt mặc định
daonb

61
Cách tiếp cận này có nghĩa là bạn có mã không đảo ngược đang chạy trong phát triển và sản xuất. Và mỗi nhà phát triển có một cơ sở mã khác nhau. Tôi gọi chống mẫu ở đây.
pydanny

8
@pydanny Vấn đề là Django lưu cấu hình của nó trong tệp .py. Bạn không thể mong đợi rằng tất cả các nhà phát triển và máy chủ sản xuất sẽ sử dụng cùng một cài đặt, vì vậy bạn cần thay đổi tệp .py này hoặc thực hiện một số giải pháp thay thế (tệp .ini, môi trường, v.v.).
Tupteq

3
Tôi thích gọi mô-đun thay settings_locallocal_settingsnhóm nó settings.pytrong danh sách thư mục theo thứ tự chữ cái. Tránh settings_local.pyxa kiểm soát phiên bản bằng cách sử dụng .gitignorethông tin đăng nhập không thuộc về Git. Hãy tưởng tượng mở nguồn cho họ một cách tình cờ. Tôi giữ trong git một tệp mẫu được gọi settings_local.py.txtthay thế.
ngắt dòng

297

Two Scoops of Django: Thực tiễn tốt nhất cho Django 1.5 đề xuất sử dụng kiểm soát phiên bản cho các tệp cài đặt của bạn và lưu trữ các tệp trong một thư mục riêng:

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

Các base.pytập tin chứa các tùy chọn chung (chẳng hạn như MEDIA_ROOT hoặc ADMIN), trong khi local.pyproduction.pycó các cài đặt trang web cụ thể:

Trong tệp cơ sở settings/base.py:

INSTALLED_APPS = (
    # common apps...
)

Trong tệp cài đặt phát triển cục bộ settings/local.py:

from project.settings.base import *

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

Trong tệp cài đặt sản xuất tệp settings/production.py :

from project.settings.base import *

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

Sau đó, khi bạn chạy django, bạn thêm --settings tùy chọn:

# 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

Các tác giả của cuốn sách cũng đã đưa ra một mẫu bố cục dự án mẫu trên Github.


62
Lưu ý rằng thay vì sử dụng --settingsmọi lúc, bạn có thể đặt DJANGO_SETTINGS_MODULEenvvar. Điều này hoạt động độc đáo với, ví dụ, Heroku: đặt nó trên toàn cầu thành sản xuất, sau đó ghi đè lên nó bằng dev trong tệp .env của bạn.
Simon Weber

9
Sử dụng DJANGO_SETTINGS_MODULEenv var là ý tưởng tốt nhất ở đây, cảm ơn Simon.
kibibu

20
Bạn có thể cần thay đổi BASE_DIRcài đặt thànhos.path.dirname(os.path.realpath(os.path.dirname(__file__) + "/.."))
Petr Peller

5
@rsp theo tài liệu django, bạn nhập from django.conf import settingslà đối tượng trừu tượng hóa giao diện và tách mã từ vị trí cài đặt, docs.djangoproject.com/en/dev/topics/sinstall/ tựa

3
Nếu tôi đặt DJANGO_SETTINGS_MODULE thông qua một biến môi trường, tôi vẫn cần os.envir.setdefault ("DJANGO_SETTINGS_MODULE", "projectname.sinstall.production") trong tệp wsgi.py của tôi chứ? Ngoài ra, tôi đã đặt var môi trường bằng cách sử dụng: export DJANGO_SETTINGS_MODULE = projectname.sinstall.local, nhưng sau đó nó bị mất khi tôi đóng thiết bị đầu cuối. Tôi có thể làm gì để đảm bảo nó được lưu? Tôi có nên thêm dòng đó vào tệp bashrc không?
Kritz

71

Thay vì settings.pysử dụng bố cục này:

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

common.py là nơi mà hầu hết các cấu hình của bạn sống.

prod.py nhập mọi thứ từ phổ biến và ghi đè bất cứ thứ gì cần ghi đè:

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

# Production overrides
DEBUG = False
#...

Tương tự, dev.pynhập mọi thứ từcommon.py và ghi đè bất cứ thứ gì nó cần để ghi đè.

Cuối cùng, __init__.pylà nơi bạn quyết định tải cài đặt nào và đó cũng là nơi bạn lưu trữ bí mật (do đó tệp này không nên được phiên bản):

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

Điều tôi thích về giải pháp này là:

  1. Mọi thứ đều nằm trong hệ thống phiên bản của bạn, ngoại trừ bí mật
  2. Hầu hết cấu hình nằm ở một nơi: common.py .
  3. Những thứ cụ thể đi vào prod.py, những thứ cụ thể đi vàodev.py . Thật đơn giản.
  4. Bạn có thể ghi đè nội dung từ common.pytrong prod.pyhoặc dev.py, và bạn có thể ghi đè mọi thứ trong__init__.py .
  5. Đó là con trăn đơn giản. Không có hack nhập lại.

2
Tôi vẫn đang cố gắng tìm ra những gì cần thiết lập trong các tệp project.wsgi và Manage.txt của mình cho tệp cài đặt. Bạn sẽ làm sáng tỏ điều này? Cụ thể, trong tệp Manage.txt của tôi, tôi có os.environ.setdefault("DJANGO_SETTINGS_MODULE", "foobar.settings")foobar là một thư mục chứa __init__.pytệp và cài đặt là một thư mục __init__.pychứa tệp chứa bí mật của tôi và nhập dev.txt, sau đó nhập common.txt. EDIT Nevermind, tôi đã không cài đặt một mô-đun được yêu cầu. Lỗi của tôi! Điều này làm việc tuyệt vời !!
teewuane

5
Hai điều: 1) tốt hơn để đặt Debug = True trong dev.txt của bạn thay vì = Sai trong prod.py của bạn. 2) Thay vì chuyển đổi trong init .py, hãy chuyển đổi bằng cách sử dụng môi trường DJANGO_SETTINGS_MODULE var. Điều này sẽ giúp triển khai PAAS (ví dụ Heroku).
Rob Grant

Khi tôi sử dụng thiết lập này trong django 1.8.4 và dùng thử máy chủ, tôi nhận được "django.core.exceptions.ImproperlyConfigured: Cài đặt SECRET_KEY không được để trống.", Ngay cả khi tôi có SECRET_KEY trên tệp init .py của tôi . Tui bỏ lỡ điều gì vậy?
Polarcare

không phải là việc sử dụng một cái gì đó như AWS_SECRET_ACCESS_KEY = os.getenv ("AWS_SECRET_ACCESS_KEY") an toàn hơn? Câu hỏi trung thực - Tôi biết lý do tại sao bạn không muốn phiên bản này, nhưng cách khác là lấy nó từ môi trường. Tất nhiên, điều này đặt ra câu hỏi về việc thiết lập biến môi trường, nhưng điều đó có thể để lại cho cơ chế triển khai của bạn, phải không?
JL Peyret

20

Tôi sử dụng một phiên bản sửa đổi một chút của kiểu cài đặt "if DEBUG" mà Harper Shelby đã đăng. Rõ ràng tùy thuộc vào môi trường (win / linux / vv.) Mã có thể cần phải được điều chỉnh một chút.

Trước đây tôi đã sử dụng "if DEBUG" nhưng tôi thấy rằng thỉnh thoảng tôi cần thực hiện kiểm tra với DEUBG được đặt thành Sai. Điều tôi thực sự muốn phân biệt nếu môi trường là sản xuất hay phát triển, điều đó cho tôi tự do lựa chọn cấp độ 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'

Tôi vẫn coi cách cài đặt này là một công việc đang tiến hành. Tôi chưa thấy một cách nào để xử lý các cài đặt Django bao trùm tất cả các cơ sở và đồng thời không phải là một rắc rối để thiết lập (Tôi không thất vọng với các phương pháp tệp cài đặt 5x).


Đây là loại điều mà các cài đặt của Django là một tệp mã thực tế cho phép và tôi đã gợi ý. Tôi đã không làm bất cứ điều gì như thế này cho mình, nhưng nó chắc chắn là loại giải pháp có thể là một câu trả lời chung tốt hơn của tôi.
Harper Shelby

3
Tôi mới gặp vấn đề này lần đầu tiên và chọn (thành công!) Sử dụng giải pháp của bạn, với một sự khác biệt nhỏ: Tôi đã sử dụng uuid.getnode () để tìm uuid trong hệ thống của mình. Vì vậy, tôi đang kiểm tra nếu uuid.getnode () == 12345678901 (thực tế là một số khác) thay vì kiểm tra os.envir bạn đã sử dụng. Tôi không thể tìm thấy sự thuyết phục để thuyết phục tôi rằng os.envir ['COMPUTERNAME'] là duy nhất cho mỗi máy tính.
Joe Golton

os.envir ['COMPUTERNAME'] không hoạt động trên Ubuntu AWS Ubuntu. Tôi nhận được một KeyError.
nu everest

Khi sử dụng UUID, giải pháp này đã được chứng minh là tốt nhất và đơn giản nhất đối với tôi. Nó không đòi hỏi nhiều sự chắp vá phức tạp và quá mức. Trong môi trường sản xuất, bạn vẫn cần đặt mật khẩu cơ sở dữ liệu và SECRET_KEY vào một tệp riêng biệt nằm ngoài kiểm soát phiên bản.
nu everest

os.environ['COMPUTERNAME']tiếc là không hoạt động trên PythonAnywhere. Bạn nhận được một KeyError.
nbeuchat

14

Tôi sử dụng settings_local.py và settings_production.py. Sau khi thử một vài tùy chọn, tôi thấy rằng thật dễ dàng để lãng phí thời gian với các giải pháp phức tạp khi chỉ cần có hai tệp cài đặt sẽ cảm thấy dễ dàng và nhanh chóng.

Khi bạn sử dụng mod_python / mod_wsgi cho dự án Django của bạn, bạn cần trỏ nó vào tệp cài đặt của bạn. Nếu bạn trỏ nó đến app / settings_local.py trên máy chủ cục bộ của bạn và app / settings_production.py trên máy chủ sản xuất của bạn thì cuộc sống sẽ trở nên dễ dàng. Chỉ cần chỉnh sửa tệp cài đặt thích hợp và khởi động lại máy chủ (máy chủ phát triển Django sẽ tự động khởi động lại).


2
Và những gì về máy chủ phát triển địa phương? Có cách nào để nói với máy chủ web django (chạy bằng cách sử dụng python manage.py runserver), tập tin cài đặt nào sẽ sử dụng?
akv

2
@akv nếu bạn thêm --sinstall = [tên mô-đun] (không có phần mở rộng .py) vào cuối lệnh máy chủ, bạn có thể chỉ định tệp cài đặt nào sẽ sử dụng. Nếu bạn sẽ làm điều đó, hãy tạo cho mình một ưu tiên và tạo một tập lệnh shell / tập tin shell với các cài đặt phát triển được định cấu hình. Tin tôi đi, những ngón tay của bạn sẽ cảm ơn bạn.
T. Stone

đây là giải pháp tôi sử dụng hack một tập tin cài đặt được sử dụng cho cả sản xuất hoặc phát triển là một
mớ

4
Tôi nghĩ sẽ tốt hơn nếu sử dụng settings.txt trong quá trình phát triển, vì bạn không phải chỉ định nó mọi lúc.
Andre Bossard

Tôi có đúng không khi cho rằng phương pháp này yêu cầu nhập mô-đun cài đặt qua proxy, django.conf.sinstall? Nếu không, bạn cần chỉnh sửa khai báo nhập để trỏ vào tệp cài đặt chính xác khi đẩy trực tiếp.
Groady

8

TL; DR: Thủ thuật là sửa đổi os.environmenttrước khi bạn nhập settings/base.pybất kỳ settings/<purpose>.py, điều này sẽ đơn giản hóa rất nhiều thứ.


Chỉ cần suy nghĩ về tất cả các tập tin đan xen này làm tôi đau đầu. Kết hợp, nhập (đôi khi có điều kiện), ghi đè, vá những gì đã được đặt trong trường hợp DEBUGcài đặt thay đổi sau này. Thật là một cơn ác mộng!

Qua nhiều năm tôi đã trải qua tất cả các giải pháp khác nhau. Tất cả họ đều có phần việc, nhưng rất đau đớn để quản lý. WTF! Chúng ta có thực sự cần tất cả những rắc rối đó? Chúng tôi bắt đầu chỉ với một settings.pytập tin. Bây giờ chúng ta cần một tài liệu chỉ để kết hợp chính xác tất cả những thứ này lại với nhau theo đúng thứ tự!

Tôi hy vọng cuối cùng tôi đã đạt được điểm ngọt ngào (của tôi) với giải pháp dưới đây.

Hãy tóm tắt lại các mục tiêu (một số thông thường, một số của tôi)

  1. Giữ bí mật một bí mật - đừng lưu trữ chúng trong một repo!

  2. Đặt / đọc khóa và bí mật thông qua cài đặt môi trường, kiểu 12 yếu tố .

  3. Có mặc định dự phòng hợp lý. Lý tưởng cho sự phát triển địa phương, bạn không cần thêm gì ngoài mặc định.

  4. Sầu nhưng cố gắng giữ mặc định sản xuất an toàn. Tốt hơn là bỏ lỡ một ghi đè cài đặt cục bộ, hơn là phải nhớ điều chỉnh các cài đặt mặc định an toàn cho sản xuất.

  5. Có khả năng bật DEBUG/ tắt theo cách có thể có ảnh hưởng đến các cài đặt khác (ví dụ: sử dụng javascript có nén hay không).

  6. Chuyển đổi giữa các cài đặt mục đích, như cục bộ / thử nghiệm / dàn / sản xuất, chỉ nên dựa trên DJANGO_SETTINGS_MODULE, không có gì hơn.

  7. Khác nhưng cho phép tham số hóa thêm thông qua các cài đặt môi trường như thế nào DATABASE_URL.

  8. Cẩu cũng cho phép họ sử dụng các cài đặt mục đích khác nhau và chạy chúng cục bộ cạnh nhau, vd. thiết lập sản xuất trên máy phát triển cục bộ, để truy cập cơ sở dữ liệu sản xuất hoặc kiểm tra kiểu bảng nén khói.

  9. Thất bại nếu một biến môi trường không được đặt rõ ràng (yêu cầu giá trị trống tối thiểu), đặc biệt là trong sản xuất, ví dụ. EMAIL_HOST_PASSWORD.

  10. Trả lời DJANGO_SETTINGS_MODULEcài đặt mặc định trong Manage.txt trong khi khởi động django-admin

  11. Giữ điều kiện đến mức tối thiểu, nếu điều kiện là các loại môi trường có mục tiêu (ví dụ. Phục vụ sản xuất bộ file log và nó xoay), cài đặt ghi đè trong liên cài đặt tập tin có mục tiêu.

Đừng

  1. Đừng để django đọc cài đặt DJANGO_SETTINGS_MODULE tạo thành một tệp.
    Ừ! Hãy nghĩ về cách meta này là. Nếu bạn cần phải có một tệp (như docker env) hãy đọc nó vào môi trường trước khi bắt đầu một quá trình django.

  2. Không ghi đè DJANGO_SETTINGS_MODULE trong mã dự án / ứng dụng của bạn, vd. dựa trên tên máy chủ hoặc tên quá trình.
    Nếu bạn lười thiết lập biến môi trường (như for setup.py test), hãy thực hiện công cụ này ngay trước khi bạn chạy mã dự án.

  3. Tránh ma thuật và vá cách django đọc cài đặt của nó, xử lý trước các cài đặt nhưng không can thiệp sau đó.

  4. Không có logic dựa trên logic phức tạp. Cấu hình nên được cố định và vật chất hóa không được tính toán khi đang bay. Cung cấp một mặc định dự phòng là đủ logic ở đây.
    Bạn có thực sự muốn gỡ lỗi, tại sao tại địa phương bạn có bộ cài đặt chính xác nhưng trong sản xuất trên một máy chủ từ xa, trên một trong hàng trăm máy, một cái gì đó được tính toán khác nhau? Oh! Bài kiểm tra đơn vị? Để cài đặt? Nghiêm túc?

Giải pháp

Chiến lược của tôi bao gồm xuất sắc django-environ sử dụng với inicác file phong cách, cung cấp os.environment, một số tối thiểu và ngắn giá trị mặc định cho sự phát triển địa phương settings/<purpose>.pytập tin có một import settings/base.py SAU sự os.environmentđược thành lập từ một INItập tin. Điều này có hiệu quả cung cấp cho chúng tôi một loại tiêm cài đặt.

Mẹo ở đây là sửa đổi os.environmenttrước khi bạn nhập settings/base.py.

Để xem ví dụ đầy đủ, hãy thực hiện repo: https://github.com/wooyek/django-sinstall-strargety

.
   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

cài đặt / .env

Một mặc định cho sự phát triển địa phương. Một tập tin bí mật, chủ yếu là thiết lập các biến môi trường cần thiết. Đặt chúng thành các giá trị trống nếu chúng không được yêu cầu trong phát triển cục bộ. Chúng tôi cung cấp mặc định ở đây và không settings/base.pybị lỗi trên bất kỳ máy nào khác nếu thiếu từ môi trường.

cài đặt / local.py

Điều gì xảy ra ở đây, là tải môi trường từ settings/.env, sau đó nhập cài đặt chung từ đó settings/base.py. Sau đó, chúng ta có thể ghi đè một số để giảm bớt sự phát triển cục bộ.

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

cài đặt / sản xuất

Để sản xuất, chúng ta không nên mong đợi một tệp môi trường, nhưng sẽ dễ dàng hơn nếu có một tệp nào đó. Nhưng dù sao đi nữa, e rằng sẽ cung cấp một vài giá trị mặc định nội tuyến, do đó settings/base.pycó thể đáp ứng tương ứng.

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

Điểm quan tâm chính ở đây là DEBUGASSETS_DEBUGghi đè, chúng sẽ được áp dụng cho con trăn os.environCHỈ nếu chúng BỎ L from từ môi trường và tệp.

Đây sẽ là các mặc định sản xuất của chúng tôi, không cần phải đặt chúng vào môi trường hoặc tệp, nhưng chúng có thể bị ghi đè nếu cần. Khéo léo!

cài đặt / cơ sở

Đây là các cài đặt django vanilla chủ yếu của bạn, với một vài điều kiện và rất nhiều đọc chúng từ môi trường. Hầu hết mọi thứ đều ở đây, giữ cho tất cả các môi trường có mục đích nhất quán và giống nhau nhất có thể.

Sự khác biệt chính là dưới đây (tôi hy vọng đây là tự giải thích):

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',)

Bit cuối cùng cho thấy sức mạnh ở đây. ASSETS_DEBUGcó một mặc định hợp lý, có thể bị ghi đè settings/production.pyvà thậm chí có thể bị ghi đè bởi cài đặt môi trường! Yay!

Trong thực tế, chúng tôi có một hệ thống phân cấp quan trọng hỗn hợp:

  1. settings / .py - đặt mặc định dựa trên mục đích, không lưu trữ bí mật
  2. settings / base.py - chủ yếu được kiểm soát bởi môi trường
  3. xử lý cài đặt môi trường - 12 yếu tố bé!
  4. settings / .env - mặc định cục bộ để dễ dàng khởi động

Này Janusz ... vậy trong tệp .env sẽ đi tất cả các khóa API và khóa xác thực và mật khẩu, v.v.? Giống như TWILLIO_API = "abc123"? Hoặc TWILLIO_API = env ("TWILLIO_API")?
dbinott

Có, nhưng đây chỉ là một dự phòng cho các thiết lập môi trường. Tệp này có ích để phát triển nhưng không được lưu trong repo hoặc được đẩy vào sản xuất khi bạn nên sử dụng nghiêm ngặt các cài đặt môi trường hoặc nền tảng tương đương sẽ lần lượt đặt cài đặt môi trường cho quy trình máy chủ.
Janusz Skonieczny

7

Tôi quản lý các cấu hình của mình với sự trợ giúp của django-split-settings .

Nó là một sự thay thế thả xuống cho các thiết lập mặc định. Nó là đơn giản, nhưng cấu hình. Và tái cấu trúc các cài đặt exisitng của bạn là không cần thiết.

Đây là một ví dụ nhỏ (tệp 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()
    )

Đó là nó.

Cập nhật

Tôi đã viết một bài đăng trên blog về việc quản lý djangocài đặt của django-split-sttings. Có một cái nhìn!


1
Tôi đã thử điều đó .. chạy vào tường một lần khi tôi cố chạy các bài kiểm tra đơn vị django của mình .. tôi chỉ không thể tìm ra cách chỉ định tệp cài đặt nào sẽ đọc từ
abbood

Tôi đã tạo một ý chính cho bạn: gist.github.com/sobolevn/006c734f0520439a4b6c16891d65406c
sobolevn

Tôi đã nhận được một cái gì đó như thế này trong mã của mình, vì vậy tôi kiểm tra cờ cài đặt.DEBUG để biết liệu tôi có muốn nhập nội dung không .. cờ đó luôn được đặt thành sai trong các thử nghiệm đơn vị django (xem tại đây ) để công việc của tôi là ghi đè chúng tại mỗi bài kiểm tra như vậy
abbood

Tuy nhiên, đây là một câu hỏi khác: uwsgi.initệp của tôi có các cài đặt khác nhau trên dev / prod .. có ý tưởng nào về cách làm cho nó chọn giá trị từ tệp cài đặt của tôi không?
abbood

xin lỗi, tôi không nhận được thiết lập bạn có thể hỏi một câu hỏi riêng với nhiều chi tiết hơn và tôi sẽ cố gắng giúp bạn.
sobolevn

6

Vấn đề với hầu hết các giải pháp này là bạn có áp dụng cài đặt cục bộ của mình trước các giải pháp chung hoặc sau chúng.

Vì vậy, không thể ghi đè những thứ như

  • cài đặt dành riêng cho env xác định địa chỉ cho nhóm memcached và trong tệp cài đặt chính, giá trị này được sử dụng để định cấu hình phụ trợ bộ đệm
  • cài đặt dành riêng cho env thêm hoặc xóa ứng dụng / phần mềm trung gian về cài đặt mặc định

đồng thời.

Một giải pháp có thể được thực hiện bằng cách sử dụng các tệp cấu hình kiểu "ini" với lớp ConfigParser. Nó hỗ trợ nhiều tệp, nội suy chuỗi lười biếng, giá trị mặc định và rất nhiều tính năng khác. Khi một số tệp đã được tải, nhiều tệp có thể được tải và giá trị của chúng sẽ ghi đè lên các tệp trước đó, nếu có.

Bạn tải một hoặc nhiều tệp cấu hình, tùy thuộc vào địa chỉ máy, biến môi trường và thậm chí các giá trị trong tệp cấu hình được tải trước đó. Sau đó, bạn chỉ cần sử dụng các giá trị được phân tích cú pháp để điền vào các cài đặt.

Một chiến lược tôi đã sử dụng thành công là:

  • Tải một defaults.initập tin mặc định
  • Kiểm tra tên máy và tải tất cả các tệp khớp với FQDN đảo ngược, từ khớp ngắn nhất đến khớp dài nhất (vì vậy, tôi đã tải net.ini, sau net.domain.iniđó net.domain.webserver01.ini, mỗi tệp có thể ghi đè các giá trị trước đó). Tài khoản này cũng dành cho các máy của nhà phát triển, vì vậy mỗi người có thể thiết lập trình điều khiển cơ sở dữ liệu ưa thích của mình, v.v. để phát triển cục bộ
  • Kiểm tra xem có "tên cụm" được khai báo không, và trong trường hợp đó tải cluster.cluster_name.ini, có thể xác định những thứ như cơ sở dữ liệu và bộ đệm IP

Như một ví dụ về điều gì đó bạn có thể đạt được với điều này, bạn có thể xác định giá trị "tên miền phụ" cho mỗi env, sau đó được sử dụng trong cài đặt mặc định (như hostname: %(subdomain).whatever.net) để xác định tất cả tên máy chủ và cookie mà django cần để hoạt động.

Đây là DRY tôi có thể nhận được, hầu hết các tệp (hiện có) chỉ có 3 hoặc 4 cài đặt. Trên hết, tôi phải quản lý cấu hình khách hàng, do đó, một tập hợp các tệp cấu hình bổ sung (với những thứ như tên cơ sở dữ liệu, người dùng và mật khẩu, tên miền phụ được gán, v.v.) đã tồn tại, một hoặc nhiều cho mỗi khách hàng.

Người ta có thể chia tỷ lệ này ở mức thấp hoặc cao đến mức cần thiết, bạn chỉ cần đặt vào tệp cấu hình các khóa bạn muốn định cấu hình cho từng môi trường và khi cần cấu hình mới, hãy đặt giá trị trước đó vào cấu hình mặc định và ghi đè lên khi cần thiết

Hệ thống này đã được chứng minh là đáng tin cậy và hoạt động tốt với kiểm soát phiên bản. Nó đã được sử dụng trong thời gian dài để quản lý hai cụm ứng dụng riêng biệt (15 phiên bản riêng biệt của trang django trên mỗi máy), với hơn 50 khách hàng, trong đó các cụm thay đổi kích thước và thành viên tùy thuộc vào tâm trạng của sysadmin .. .


1
Bạn có một ví dụ về cách bạn tải các cài đặt từ ini vào cài đặt của Django không?
kaleissin

Xem docs.python.org/2/l Library / configparser.html . Bạn có thể tải một trình phân tích cú pháp config = ConfigParser.ConfigParser() sau đó đọc các tệp của bạn config.read(array_of_filenames)và nhận các giá trị bằng cách sử dụng config.get(section, option). Vì vậy, trước tiên bạn tải cấu hình của mình và sau đó bạn sử dụng nó để đọc các giá trị cho cài đặt.
viết lại

5

Tôi cũng đang làm việc với Laravel và tôi thích việc thực hiện ở đó. Tôi đã cố gắng bắt chước nó và kết hợp nó với giải pháp do T. Stone đề xuất (xem ở trên):

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

Có lẽ một cái gì đó như thế này sẽ giúp bạn.


4

Hãy nhớ rằng settings.txt là một tệp mã trực tiếp. Giả sử rằng bạn không cài đặt DEBUG cho sản xuất (đây là cách thực hành tốt nhất), bạn có thể thực hiện một số việc như:

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

Về cơ bản, về lý thuyết, bạn có thể đi đến bất kỳ mức độ phức tạp nào chỉ dựa trên giá trị của DEBUG - hoặc bất kỳ biến hoặc mã nào khác mà bạn muốn sử dụng.


4

Đối với hầu hết các dự án của tôi, tôi sử dụng mẫu sau:

  1. Tạo settings_base.py nơi tôi lưu trữ các cài đặt phổ biến cho tất cả các môi trường
  2. Bất cứ khi nào tôi cần sử dụng môi trường mới với các yêu cầu cụ thể, tôi tạo tệp cài đặt mới (ví dụ: settings_local.py) kế thừa nội dung của settings_base.py và ghi đè / thêm các biến cài đặt thích hợp ( from settings_base import *)

(Để chạy manage.py với các thiết lập tùy chỉnh tập tin bạn chỉ cần sử dụng tùy chọn lệnh --settings: manage.py <command> --settings=settings_you_wish_to_use.py)


3

Giải pháp của tôi cho vấn đề đó cũng phần nào là sự pha trộn của một số giải pháp đã được nêu ở đây:

  • Tôi giữ một tập tin được gọi là local_settings.pycó nội dung USING_LOCAL = Truetrong dev và USING_LOCAL = Falseprod
  • Trong settings.pytôi thực hiện nhập vào tệp đó để có được USING_LOCALcài đặt

Sau đó, tôi dựa trên tất cả các cài đặt phụ thuộc vào môi trường của mình vào đó:

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

Tôi thích điều này hơn khi có hai tệp cài đặt riêng biệt mà tôi cần duy trì vì tôi có thể giữ các cài đặt của mình được cấu trúc trong một tệp dễ dàng hơn so với việc chúng trải rộng trên một số tệp. Như thế này, khi tôi cập nhật một cài đặt, tôi không quên thực hiện nó cho cả hai môi trường.

Tất nhiên mọi phương pháp đều có nhược điểm của nó và phương pháp này cũng không ngoại lệ. Vấn đề ở đây là tôi không thể ghi đè lên local_settings.pytệp bất cứ khi nào tôi thay đổi sản phẩm của mình, nghĩa là tôi không thể sao chép tất cả các tệp một cách mù quáng, nhưng đó là thứ tôi có thể sống cùng.


3

Tôi sử dụng một biến thể của những gì jpartogi đã đề cập ở trên, mà tôi thấy ngắn hơn một chút:

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)

Về cơ bản trên mỗi máy tính (phát triển hoặc sản xuất) tôi có tệp hostname_sinstall.py thích hợp được tải động.



3

1 - Tạo một thư mục mới bên trong ứng dụng và cài đặt tên cho nó.

2 - Bây giờ tạo một __init__.pytệp mới trong đó và bên trong nó viết

from .base import *

try:
    from .local import *
except:
    pass

try:
    from .production import *
except:
    pass

3 - Tạo ba file mới trong thư mục cài đặt tên local.pyproduction.pybase.py.

4 - Bên trong base.py, sao chép tất cả nội dung của settings.pythư mục trước đó và đổi tên nó với nội dung khác, giả sử old_settings.py.

5 - Trong cơ sở, hãy thay đổi đường dẫn BASE_DIR của bạn để trỏ đến đường dẫn cài đặt mới của bạn

Con đường cũ-> BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Đường dẫn mới -> BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Bằng cách này, thư mục dự án có thể được cấu trúc và có thể quản lý được giữa sản xuất và phát triển địa phương.


2

Để sử dụng settingscấu hình khác nhau trên môi trường khác nhau, hãy tạo tệp cài đặt khác nhau. Và trong tập lệnh triển khai của bạn, hãy khởi động máy chủ bằng --settings=<my-settings.py>tham số, qua đó bạn có thể sử dụng các cài đặt khác nhau trên các môi trường khác nhau.

Lợi ích của việc sử dụng phương pháp này :

  1. Cài đặt của bạn sẽ được mô đun hóa dựa trên từng môi trường

  2. Bạn có thể nhập master_settings.pycấu hình cơ sở chứa trong environmnet_configuration.pyvà ghi đè các giá trị mà bạn muốn thay đổi trong môi trường đó.

  3. Nếu bạn có một đội ngũ lớn, mỗi nhà phát triển có thể có nhóm riêng local_settings.pymà họ có thể thêm vào kho lưu trữ mã mà không có bất kỳ rủi ro nào trong việc sửa đổi cấu hình máy chủ. Bạn có thể thêm các cài đặt cục bộ này vào .gitnorenếu bạn sử dụng git hoặc .hginorenếu bạn Mercurial cho Phiên bản kiểm soát (hoặc bất kỳ cài đặt nào khác). Bằng cách đó, các thiết lập cục bộ thậm chí sẽ không phải là một phần của cơ sở mã thực tế giữ cho nó sạch sẽ.


2

Tôi đã phân chia cài đặt của mình như sau

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

Chúng tôi có 3 môi trường

  • nhà phát triển
  • dàn dựng
  • sản xuất

Bây giờ rõ ràng dàn dựng và sản xuất nên có môi trường tương tự tối đa có thể. Vì vậy, chúng tôi giữ prod.pycho cả hai.

Nhưng có một trường hợp tôi phải xác định máy chủ đang chạy là máy chủ sản xuất. @T. Câu trả lời của Stone đã giúp tôi viết séc như sau.

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

Tôi phân biệt nó trong Manage.txt và tạo hai tệp cài đặt riêng biệt: local_sinstall.py và prod_sinstall.py.

Trong Manage.txt tôi kiểm tra xem máy chủ là máy chủ cục bộ hay máy chủ sản xuất. Nếu nó là một máy chủ cục bộ, nó sẽ tải lên local_sinstall.py và nó là một máy chủ sản xuất, nó sẽ tải lên prod_sinstall.py. Về cơ bản đây là cách nó sẽ trông như thế nà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)

Tôi thấy việc tách tệp cài đặt thành hai tệp riêng biệt dễ dàng hơn thay vì thực hiện nhiều if trong tệp cài đặt.


1

Thay thế để duy trì các tệp khác nhau nếu bạn sử dụng: Nếu bạn đang sử dụng git hoặc bất kỳ VCS nào khác để đẩy mã từ cục bộ sang máy chủ, điều bạn có thể làm là thêm tệp cài đặt vào .gitignore.

Điều này sẽ cho phép bạn có nội dung khác nhau ở cả hai nơi mà không có vấn đề gì. SO trên máy chủ, bạn có thể định cấu hình phiên bản cài đặt độc lập và mọi thay đổi được thực hiện trên máy chủ cục bộ sẽ không phản ánh trên máy chủ và ngược lại.

Ngoài ra, nó cũng sẽ xóa tệp settings.txt khỏi github, lỗi lớn mà tôi đã thấy nhiều người mới đang làm.



0

Tôi nghĩ rằng giải pháp tốt nhất được đề xuất bởi @T. Đá, nhưng tôi không biết tại sao chỉ không sử dụng cờ DEBUG trong Django. Tôi viết mã dưới đây cho trang web của tôi:

if DEBUG:
    from .local_settings import *

Luôn luôn là những giải pháp đơn giản tốt hơn những giải pháp phức tạp.


-2

Tôi tìm thấy các câu trả lời ở đây rất hữu ích. (Điều này đã được giải quyết dứt khoát hơn chưa? Phản hồi cuối cùng là một năm trước.) Sau khi xem xét tất cả các phương pháp được liệt kê, tôi đã đưa ra một giải pháp mà tôi không thấy được liệt kê ở đây.

Tiêu chí của tôi là:

  • Tất cả mọi thứ nên được kiểm soát nguồn. Tôi không thích những thứ vớ vẩn nằm xung quanh.
  • Lý tưởng nhất là giữ các thiết lập trong một tập tin. Tôi quên mọi thứ nếu tôi không nhìn thẳng vào chúng :)
  • Không chỉnh sửa thủ công để triển khai. Có thể kiểm tra / đẩy / triển khai với một lệnh vải duy nhất.
  • Tránh rò rỉ cài đặt phát triển vào sản xuất.
  • Giữ càng gần càng tốt với bố cục Django "chuẩn" (* ho *) càng tốt.

Tôi nghĩ chuyển đổi trên máy chủ có ý nghĩa gì đó, nhưng sau đó nhận ra vấn đề thực sự ở đây là các cài đặt khác nhau cho các môi trường khác nhau và đã có một khoảnh khắc. Tôi đặt mã này vào cuối tệp settings.txt của mình:

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'

Bằng cách này, ứng dụng mặc định cho các cài đặt sản xuất, có nghĩa là bạn rõ ràng "đưa danh sách trắng" vào môi trường phát triển của mình. Sẽ an toàn hơn nhiều khi quên đặt biến môi trường cục bộ so với cách khác và bạn quên đặt một cái gì đó trong sản xuất và để một số cài đặt dev được sử dụng.

Khi phát triển cục bộ, từ vỏ hoặc trong .bash_profile hoặc bất cứ nơi nào:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(Hoặc nếu bạn đang phát triển trên Windows, hãy đặt qua Bảng điều khiển hoặc bất cứ thứ gì được gọi là những ngày này ... Windows luôn làm cho nó trở nên tối nghĩa đến mức bạn có thể đặt các biến môi trường.)

Với cách tiếp cận này, các cài đặt dev đều ở một nơi (tiêu chuẩn) và chỉ cần ghi đè lên các cài đặt sản xuất khi cần thiết. Bất kỳ mucking nào với các cài đặt phát triển phải hoàn toàn an toàn để cam kết kiểm soát nguồn mà không ảnh hưởng đến sản xuất.


Tốt hơn là chỉ duy trì các tệp cấu hình khác nhau và chọn sử dụng biến env tiêu chuẩn DJango DJANGO_SETTINGS_MODULE
Rob Grant
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.