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'
from project.settings.base import *
DEBUG = True
INSTALLED_APPS += (
'debug_toolbar', # and other apps for local development
)
在文件生成设置文件_1774186中:
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
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..."
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()
)
.
│ manage.py
├───data
└───website
├───settings
│ │ __init__.py <-- imports local for compatybility
│ │ base.py <-- almost all the settings, reads from proces environment
│ │ local.py <-- a few modifications for local development
│ │ production.py <-- ideally is empy and everything is in base
│ │ testing.py <-- mimics production with a reasonable exeptions
│ │ .env <-- for local use, not kept in repo
│ __init__.py
│ urls.py
│ wsgi.py
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
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'),
}
}
}
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
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)
#!/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)
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'
20 回答
我使用了Harper Shelby发布的“if DEBUG”设置风格的略微修改版本 . 显然取决于环境(win / linux / etc.),代码可能需要稍微调整一下 .
我过去使用“if DEBUG”,但我发现偶尔需要将DEUBG设置为False进行测试 . 如果环境是 生产环境 或开发,我真的想要区分,这让我可以自由选择DEBUG级别 .
我仍然认为这种设置方式正在进行中 . 我还没有看到任何一种处理涵盖所有基础的Django设置的方法,同时也没有完全麻烦的设置(我没有使用5x设置文件方法) .
在
settings.py
:您可以覆盖
local_settings.py
中所需的内容;它应该远离你的版本控制 . 但既然你提到复制,我猜你没有使用;)Two Scoops of Django: Best Practices for Django 1.5建议对设置文件使用版本控制并将文件存储在单独的目录中:
base.py
文件包含常用设置(例如MEDIA_ROOT或ADMIN),而local.py
和production.py
包含特定于站点的设置:在基本文件
settings/base.py
中:在本地开发设置文件
settings/local.py
中:在文件生成设置文件_1774186中:
然后当你运行django时,添加
--settings
选项:这本书的作者也在Github上提出了a sample project layout template .
而不是
settings.py
,使用此布局:common.py
是您的大多数配置存在的地方 .prod.py
从常见导入所有内容,并覆盖它需要覆盖的任何内容:同样,
dev.py
从common.py
导入所有内容并覆盖它需要覆盖的任何内容 .最后,
__init__.py
是您决定加载哪些设置的地方,也是您存储机密的地方(因此不应对此文件进行版本控制):我喜欢这个解决方案是:
除了秘密之外,一切都在您的版本控制系统中
大多数配置都在一个地方:
common.py
.特定于Prod的东西进入
prod.py
,特定于dev的东西进入dev.py
. 这很简单 .您可以在
prod.py
或dev.py
中覆盖common.py
中的内容,并且可以覆盖__init__.py
中的任何内容 .这是简单的python . 没有重新进口黑客 .
我使用了settings_local.py和settings_production.py . 在尝试了几个选项之后,我发现只需简单地让两个设置文件感觉简单快捷,就很容易浪费时间使用复杂的解决方案 .
当您为Django项目使用mod_python / mod_wsgi时,您需要将其指向您的设置文件 . 如果您将其指向本地服务器上的app / settings_local.py和 生产环境 服务器上的app / settings_production.py,那么生活将变得轻松 . 只需编辑相应的设置文件并重新启动服务器(Django开发服务器将自动重启) .
我在django-split-settings的帮助下管理我的配置 .
它是默认设置的替代品 . 它很简单,但可配置 . 并且不需要重构您的现有设置 .
这是一个小例子(文件
example/settings/__init__.py
):而已 .
更新
我写了blog post关于用
django-split-sttings
管理django
的设置 . 看一看!大多数这些解决方案的问题在于,您可以在常用设置之前应用本地设置,也可以在应用之后应用本地设置 .
所以不可能覆盖像这样的东西
特定于env的设置定义了memcached池的地址,在主设置文件中,该值用于配置缓存后端
特定于env的设置将应用程序/中间件添加或删除为默认值一
同时 .
可以使用ConfigParser类使用“ini”式配置文件来实现一个解决方案 . 它支持多个文件,惰性字符串插值,默认值和许多其他好东西 . 一旦加载了许多文件,就可以加载更多的文件,如果有的话,它们的值将覆盖以前的文件 .
您加载一个或多个配置文件,具体取决于机器地址,环境变量甚至以前加载的配置文件中的值 . 然后,您只需使用已解析的值来填充设置 .
我成功使用的一个策略是:
加载默认
defaults.ini
文件检查机器名称,并加载与反向FQDN匹配的所有文件,从最短匹配到最长匹配(因此,我加载
net.ini
,然后net.domain.ini
,然后net.domain.webserver01.ini
,每个可能覆盖前一个的值) . 此帐户也适用于开发人员的计算机,因此每个人都可以为本地开发设置其首选数据库驱动程序等检查是否有"cluster name"声明,在这种情况下加载
cluster.cluster_name.ini
,它可以定义数据库和缓存IP之类的东西作为您可以通过此实现的一个示例,您可以定义一个_ -1774220_值per-env,然后在默认设置(如
hostname: %(subdomain).whatever.net
)中使用它来定义django需要工作的所有必需的主机名和cookie .这就像我可以获得的干,大多数(现有)文件只有3或4个设置 . 除此之外,我必须管理客户配置,因此存在一组额外的配置文件(包括数据库名称,用户和密码,分配的子域等),每个客户一个或多个 .
可以根据需要将其扩展为低或高,只需在配置文件中输入要为每个环境配置的密钥,并且一旦需要新配置,将先前的值放在默认配置中,并覆盖它在必要时 .
该系统经证明可靠,可与版本控制配合使用 . 它已被用于长时间管理两个独立的应用程序集群(每台机器的15个或更多单独的django站点实例),有超过50个客户,其中集群根据系统管理员的情绪改变大小和成员 . .
TL; DR:诀窍是在任何
settings/<purpose>.py
中导入settings/base.py
之前修改os.environment
,这将大大简化一些事情 .想到所有这些交织在一起的文件让我很头疼 . 组合,导入(有时是有条件的),覆盖,修补已经设置的情况
DEBUG
设置稍后更改 . 什么样的恶梦!多年来,我经历了所有不同的解决方案 . 他们都有点工作,但管理起来很痛苦 . WTF!我们真的需要一切麻烦吗?我们从一个
settings.py
文件开始 . 现在我们需要一个文档才能正确地将所有这些组合在一起!我希望我终于用下面的解决方案击中(我的)最佳位置 .
让我们回顾一下目标(一些常见的,一些是我的)
保密秘密 - 不要将它们存放在回购中 .
通过环境设置设置/读取密钥和密钥,12 factor style .
有合理的后备默认值 . 理想情况下,对于本地开发,除默认值之外不需要任何其他内容 .
...但尝试保持默认 生产环境 安全 . 最好错过本地设置覆盖,而不是必须记住调整 生产环境 安全的默认设置 .
能够以对其他设置产生影响的方式打开/关闭
DEBUG
(例如,使用javascript压缩或不压缩) .在目的设置(如本地/测试/暂存/ 生产环境 )之间切换应仅基于
DJANGO_SETTINGS_MODULE
,仅此而已 ....但允许通过
DATABASE_URL
等环境设置进一步参数化 ....还允许他们使用不同的目的设置并在本地并排运行,例如 . 本地开发人员机器上的 生产环境 设置,访问 生产环境 数据库或烟雾测试压缩样式表 .
如果未明确设置环境变量(最低要求空值),则失败,尤其是在 生产环境 中,例如 .
EMAIL_HOST_PASSWORD
.在django-admin startproject期间回复在manage.py中设置的默认
DJANGO_SETTINGS_MODULE
如果条件是目的环境类型(例如,对于 生产环境 集日志文件及其旋转),则将条件保持为最小值,覆盖相关目的设置文件中的设置 .
不要
不要让django读取DJANGO_SETTINGS_MODULE设置表单文件 .
啊!想想这是多么美好 . 如果您需要在启动django进程之前将文件(如docker env)读入环境中 .
不要覆盖项目/应用程序代码中的DJANGO_SETTINGS_MODULE,例如 . 基于主机名或进程名称 .
如果您懒于设置环境变量(例如
setup.py test
),请在运行项目代码之前在工具中执行此操作 .避免魔术和修补django如何读取它的设置,预处理设置但不会干扰 .
没有复杂的基于逻辑的废话 . 配置应该是固定的,具体化不是动态计算的 . 提供回退默认值就足够了 .
你真的想调试吗,为什么本地你有正确的设置,但在远程服务器上 生产环境 ,在一百台机器上,计算方式不同?哦!单元测试?对于设置?真的吗?
解决方案
我的策略包括与
ini
样式文件一起使用的优秀django-environ,为本地开发提供os.environment
默认值,从INI
文件设置os.environment
之后有一些import settings/base.py
文件的settings/<purpose>.py
文件 . 这有效地为我们提供了一种注入设置 .这里的技巧是在导入
settings/base.py
之前修改os.environment
.要查看完整的示例,请执行回购:https://github.com/wooyek/django-settings-strategy
settings / .env
本地开发的默认值 . 一个秘密文件,主要用于设置所需的环境变量 . 如果在本地开发中不需要它们,则将它们设置为空值 . 如果环境中缺少任何其他计算机,我们在此处提供默认值而不是
settings/base.py
中的默认值 .settings / local.py
这里发生的是从
settings/.env
加载环境,然后从settings/base.py
导入常用设置 . 之后我们可以覆盖一些以简化本地开发 .settings / production.py
对于 生产环境 ,我们不应该期望一个环境文件,但它会重新测试一些东西 . 但无论如何,以免提供内联的默认值,因此
settings/base.py
可以做出相应的响应 .这里的主要兴趣点是
DEBUG
和ASSETS_DEBUG
覆盖,如果它们从环境和文件中丢失,它们将仅应用于pythonos.environ
.这些将是我们的 生产环境 默认值,无需将它们放在环境或文件中,但如果需要,可以覆盖它们 . 整齐!
settings / base.py
这些是你的大多数香草django设置,有一些条件和很多从环境中读取它们 . 几乎所有东西都在这里,保持所有目的环境的一致性和尽可能相似 .
主要区别如下(我希望这些是不言自明的):
最后一位显示了这里的功率 .
ASSETS_DEBUG
有一个合理的默认值,可以在settings/production.py
中覆盖,甚至可以被环境设置覆盖!好极了!实际上,我们有一个重要的混合层次:
settings / .py - 根据目的设置默认值,不存储机密
settings / base.py - 主要由环境控制
流程环境设置 - 12个因素宝贝!
settings / .env - 本地默认设置,便于启动
请记住,settings.py是一个实时代码文件 . 假设您没有在 生产环境 中设置DEBUG(这是最佳做法),您可以执行以下操作:
非常基本,但理论上,你可以根据DEBUG的值 - 或者你想要使用的任何其他变量或代码检查,达到任何复杂程度 .
我也在和Laravel合作,我喜欢那里的实施 . 我试图模仿它并将其与T. Stone提出的解决方案相结合(见上文):
也许这样的事情可以帮到你 .
我对这个问题的解决方案也有点混合了这里已经说过的一些解决方案:
我保留了一个名为
local_settings.py
的文件,其中包含dev中的内容USING_LOCAL = True
和USING_LOCAL = False
中的内容在
settings.py
我对该文件进行导入以获取USING_LOCAL
设置然后,我将所有与环境相关的设置基于该设置:
我更喜欢这个有两个单独的settings.py文件,我需要维护,因为我可以将我的设置结构化在一个文件中比将它们分布在多个文件中更容易 . 像这样,当我更新设置时,我没有忘了在两种环境中都这样做 .
当然,每种方法都有其缺点,这一点也不例外 . 这里的问题是,每当我将更改推送到 生产环境 中时,我都无法覆盖
local_settings.py
文件,这意味着我可以使用't just copy all files blindly, but that' .对于我的大多数项目,我使用以下模式:
创建settings_base.py,其中我存储了所有环境通用的设置
每当我需要使用具有特定要求的新环境时,我创建新的设置文件(例如.setset_local.py),该文件继承了settings_base.py的内容并覆盖/添加了适当的设置变量(
from settings_base import *
)(要使用自定义设置文件运行manage.py,只需使用--settings命令选项:
manage.py <command> --settings=settings_you_wish_to_use.py
)我使用了上面提到的jpartogi的变体,我发现它有点短:
基本上在每台计算机(开发或 生产环境 )上我都有适当的hostname_settings.py文件,它可以动态加载 .
还有Django Classy设置 . 我个人非常喜欢它 . 它由Django IRC上最活跃的人之一构建 . 您可以使用环境变量进行设置 .
http://django-classy-settings.readthedocs.io/en/latest/
要在不同环境中使用不同的
settings
配置,请创建不同的设置文件 . 在部署脚本中,使用--settings=<my-settings.py>参数启动服务器,通过该参数可以在不同环境中使用不同的设置 .Benefits of using this approach :
您的设置将根据每个环境进行模块化
您可以在
environmnet_configuration.py
中导入包含基本配置的master_settings.py
,并覆盖要在该环境中更改的值 .如果您拥有庞大的团队,每个开发人员可能拥有自己的
local_settings.py
,他们可以将其添加到代码存储库中,而不会有任何修改服务器配置的风险 . 如果您使用git,则可以将这些本地设置添加到.gitnore
;如果您使用Mercurial进行版本控制(或任何其他),则可以将这些设置添加到.hginore
. 这样,本地设置甚至不会成为保持干净的实际代码库的一部分 .我在manage.py中区分它并创建了两个单独的设置文件:local_settings.py和prod_settings.py .
在manage.py中,我检查服务器是本地服务器还是 生产环境 服务器 . 如果它是本地服务器,它将加载local_settings.py,它是一个 生产环境 服务器,它将加载prod_settings.py . 基本上这就是它的样子:
我发现将设置文件分成两个单独的文件更容易,而不是在设置文件中做很多ifs .
作为维护不同文件的替代方法:如果您使用git或任何其他VCS将代码从本地推送到服务器,您可以做的是将设置文件添加到.gitignore .
这将允许您在两个地方都有不同的内容,没有任何问题 . 在服务器上,您可以配置settings.py的独立版本,并且在本地进行的任何更改都不会反映在服务器上,反之亦然 .
此外,它还将从github中删除settings.py文件,这是我见过许多新手所做的大错 .
我的设置分为如下
我们有3个环境
dev
分期
生产环境
现在显然,分期和 生产环境 应该具有尽可能最大的类似环境 . 所以我们两个都保持
prod.py
.但有一种情况我必须确定正在运行的服务器是一个 生产环境 服务器 . @T . 斯通的回答帮我写了如下支票 .
1 - 在应用程序中创建一个新文件夹,并为其命名设置 .
2 - 现在在其中创建一个新的 init .py文件并在其中写入
3 - 在设置文件夹名称local.py和production.py以及base.py中创建三个新文件
4 - 在base.py里面复制以前的settings.p文件夹的所有内容,并用不同的东西重命名,比如说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 )))
现在通过这种方式,项目目录可以结构化,并且可以在 生产环境 和本地开发之间进行管理 .
我发现这里的回答很有帮助 . (这是否已经得到了更明确的解决?最后一次回复是一年前的事情 . )在考虑了所有方法之后列出来了,我想出了一个我没有看到的解决方案 .
我的标准是:
一切都应该在源代码管理中 . 我不喜欢四处闲聊 .
理想情况下,将设置保存在一个文件中 . 如果我不正确看待他们,我会忘记的事情:)
无需手动编辑即可部署 . 应该能够使用单个结构命令进行测试/推送/部署 .
避免将开发设置泄漏到 生产环境 中 .
尽可能靠近"standard"(咳嗽)Django布局 .
我认为切换主机有一定意义,但后来认为这里真正的问题是针对不同环境的不同设置,并且有一个aha时刻 . 我把这段代码放在我的settings.py文件的末尾:
这样,应用程序默认为 生产环境 设置,这意味着您明确地是"whitelisting"您的开发环境 . 忘记在本地设置环境变量比使用其他方式更安全,并且忘记在 生产环境 中设置某些内容并使用某些开发设置 .
在本地开发时,无论是从shell还是在.bash_profile中,或者在以下任何地方:
(或者,如果您正在使用Windows进行开发,请通过控制面板或其他所谓的日期进行设置...... Windows总是让它变得如此模糊以至于您可以设置环境变量 . )
使用这种方法,开发设置都在一个(标准)位置,并根据需要简单地覆盖 生产环境 环境 . 任何涉及开发设置的问题应该是完全安全的,可以在不影响 生产环境 的情况下进行源代码管理 .