ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Django 中管理本地与生产设置?

处理本地开发和生产服务器设置的推荐方法是什么?其中一些(如常量等)可以在两者中更改/访问,但其中一些(如静态文件的路径)需要保持不同,因此不应在每次部署新代码时都被覆盖。

目前,我将所有常量添加到 settings.py。但是每次我在本地更改一些常量时,我都必须将其复制到生产服务器并编辑文件以进行生产特定的更改... :(

编辑:看起来这个问题没有标准答案,我接受了最流行的方法。

请查看django-configurations
被接受的方法不再是最流行的方法。
django-split-settings 非常易于使用。它不需要重写任何默认设置。
你应该使用 base.py 文件,并且在你的 local.py “from .base import *”中,在你的 production.py “from .base import *”中,你需要运行你的项目: python manage.py runserver -- settings=project_name.settings.local

g
gene_wood

Two Scoops of Django: Best Practices for 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.pyproduction.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 上发布了 a sample project layout template


请注意,您可以设置 DJANGO_SETTINGS_MODULE envvar,而不是每次都使用 --settings。这适用于例如 Heroku:将其全局设置为生产环境,然后在您的 .env 文件中使用 dev 覆盖它。
在这里使用 DJANGO_SETTINGS_MODULE env var 是最好的主意,谢谢 Simon。
您可能需要将 BASE_DIR 设置更改为 os.path.dirname(os.path.realpath(os.path.dirname(__file__) + "/.."))
@rsp 根据 django 文档,您导入 from django.conf import settings 这是一个抽象接口并将代码与设置位置解耦的对象,docs.djangoproject.com/en/dev/topics/settings/…
如果我通过环境变量设置 DJANGO_SETTINGS_MODULE,我的 wsgi.py 文件中还需要 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "projectname.settings.production") 吗?另外,我使用以下方法设置了环境变量:export DJANGO_SETTINGS_MODULE=projectname.settings.local,但是当我关闭终端时它会丢失。我能做些什么来确保它被保存?我应该将该行添加到 bashrc 文件中吗?
a
alexmuller

settings.py 中:

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

您可以覆盖 local_settings.py 中需要的内容;那么它应该远离您的版本控制。但是既然你提到了复制,我猜你什么都不用;)


为了简化新设置的跟踪/部署,请在生产/测试机器上使用“local_settings.py”,而在开发机器上不使用。
我就是这样做的——在 settings.py 的末尾添加这些行,这样它们就可以覆盖默认设置
这种方法意味着您在开发和生产中运行未版本化的代码。每个开发人员都有不同的代码库。我在这里称之为反模式。
@pydanny问题是Django将其配置存储在 .py 文件中。您不能期望所有开发人员和生产服务器都使用相同的设置,因此您需要更改此 .py 文件或实施一些替代解决方案(.ini 文件、环境等)。
我更喜欢调用模块 settings_local 而不是 local_settings,以便在按字母顺序排列的文件夹列表中将其与 settings.py 分组。使用 .gitignoresettings_local.py 排除在版本控制之外,因为凭据不属于 Git。想象一下意外地开源它们。我在 git 中保留了一个名为 settings_local.py.txt 的模板文件。
M
MiniQuark

使用以下布局代替 settings.py

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

common.py 是您的大部分配置所在的位置。

prod.py 从 common 导入所有内容,并覆盖它需要覆盖的任何内容:

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

# Production overrides
DEBUG = False
#...

同样,dev.pycommon.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..."

我喜欢这个解决方案的地方是:

一切都在您的版本控制系统中,除了秘密 大多数配置都在一个地方:common.py。特定于产品的东西放在 prod.py 中,特定于开发的东西放在 dev.py 中。这很简单。您可以覆盖 prod.py 或 dev.py 中来自 common.py 的内容,也可以覆盖 __init__.py 中的任何内容。这是简单的python。没有重新导入黑客。


我仍在尝试找出在我的 project.wsgi 和 manage.py 文件中为设置文件设置的内容。你会对此有所了解吗?具体来说,在我的 manage.py 文件中,我有 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "foobar.settings") foobar 是一个带有 __init__.py 文件的文件夹,而 settings 是一个带有 __init__.py 文件的文件夹,其中包含我的秘密并导入 dev.py,然后导入 common.py . 编辑 没关系,我没有安装所需的模块。我的错!这很好用!!
两件事:1) 最好在你的 dev.py 中设置 Debug=True 而不是在你的 prod.py 中设置 =False。 2) 不是在 init.py 中切换,而是使用 DJANGO_SETTINGS_MODULE 环境变量进行切换。这将有助于 PAAS 部署(例如 Heroku)。
当我在 django 1.8.4 中使用此设置并尝试运行服务器时,我得到“django.core.exceptions.ImproperlyConfigured:SECRET_KEY 设置不能为空。”,即使我的 init.py 文件中有 SECRET_KEY。我错过了什么吗?
使用 AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY") 之类的东西不是更安全吗?诚实的问题 - 我知道你为什么不希望它版本化,但另一种选择是从环境中获取它。当然,这引出了设置环境变量的问题,但这可以留给您的部署机制,不是吗?
T
T. Stone

我使用 Harper Shelby 发布的“if DEBUG”设置样式的略微修改版本。显然,根据环境(win/linux/etc.),代码可能需要稍作调整。

我过去使用“if DEBUG”,但我发现有时我需要在 DEUBG 设置为 False 的情况下进行测试。我真正想区分环境是生产还是开发,这让我可以自由选择 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 的设置作为实际代码文件所允许的那种事情,我在暗示。我自己没有做过这样的事情,但这绝对是一种可能比我的更好的一般答案的解决方案。
我只是第一次遇到这个问题并选择(成功!)使用您的解决方案,但略有不同:我使用 uuid.getnode() 来查找我的系统的 uuid。因此,我正在测试 uuid.getnode() == 12345678901 (实际上是不同的数字)而不是您使用的 os.environ 测试。我找不到文档来说服我 os.environ['COMPUTERNAME'] 每台计算机都是唯一的。
os.environ['COMPUTERNAME'] 在 Amazon AWS Ubuntu 上不起作用。我得到一个 KeyError。
当使用 UUID 时,这个解决方案已被证明对我来说是最好和最简单的。它不需要大量复杂和过度模块化的拼凑。在生产环境中,您仍然需要将数据库密码和 SECRET_KEY 放在位于版本控制之外的单独文件中。
os.environ['COMPUTERNAME'] 很遗憾,它不适用于 PythonAnywhere。你得到一个 KeyError。
K
Kai

我使用 settings_local.py 和 settings_production.py。在尝试了几个选项后,我发现当简单地拥有两个设置文件感觉轻松快捷时,很容易在复杂的解决方案上浪费时间。

当你为你的 Django 项目使用 mod_python/mod_wsgi 时,你需要将它指向你的设置文件。如果您将其指向本地服务器上的 app/settings_local.py 和生产服务器上的 app/settings_production.py,那么生活就会变得轻松。只需编辑适当的设置文件并重新启动服务器(Django 开发服务器将自动重新启动)。


那么本地开发服务器呢?有没有办法告诉 django 网络服务器(使用 python manage.py runserver 运行),使用哪个设置文件?
@akv 如果您将 --settings=[module name](无 .py 扩展名)添加到 runserver 命令的末尾,您可以指定要使用的设置文件。如果您要这样做,请帮自己一个忙,制作一个配置了开发设置的 shell 脚本/批处理文件。相信我,你的手指会感谢你的。
这是我使用的解决方案。破解用于生产或开发的设置文件很麻烦
我认为在开发中使用 settings.py 更好,因为您不必一直指定它。
假设此方法需要通过代理 django.conf.settings 导入设置模块,我是否正确?否则,您需要在实时推送时编辑导入声明以指向正确的设置文件。
A
A K

TL;DR:诀窍是在将 settings/base.py 导入任何 settings/<purpose>.py 之前修改 os.environment,这将大大简化事情。

光是想想所有这些交织在一起的文件就让我头疼。组合、导入(有时是有条件的)、覆盖、修补已设置的内容,以防 DEBUG 设置稍后更改。什么样的恶梦!

这些年来,我经历了所有不同的解决方案。他们都有点工作,但管理起来非常痛苦。哇!我们真的需要这么多麻烦吗?我们从一个 settings.py 文件开始。现在我们需要一个文档以正确地将所有这些以正确的顺序组合在一起!

我希望我终于用下面的解决方案达到了(我的)最佳位置。

让我们回顾一下目标(一些常见的,一些我的)

保守秘密——不要将它们存储在存储库中!通过环境设置设置/读取密钥和秘密,12 因子样式。有合理的后备默认值。理想情况下,对于本地开发,除了默认值之外,您不需要其他任何东西。 …但尽量保持默认生产安全。最好在本地错过设置覆盖,而不是必须记住调整默认设置以确保生产安全。能够以影响其他设置的方式打开/关闭调试(例如,使用或不使用压缩的 javascript)。用途设置之间的切换,如本地/测试/暂存/生产,应该仅基于 DJANGO_SETTINGS_MODULE,仅此而已。 …但允许通过 DATABASE_URL 等环境设置进行进一步参数化。 …还允许他们使用不同的目的设置并在本地并排运行它们,例如。本地开发人员机器上的生产设置,以访问生产数据库或烟雾测试压缩样式表。如果未明确设置环境变量(至少需要一个空值),则失败,尤其是在生产中,例如。 EMAIL_HOST_PASSWORD。在 django-admin startproject 期间响应在 manage.py 中设置的默认 DJANGO_SETTINGS_MODULE 将条件保持在最低限度,如果条件是目的环境类型(例如,对于生产集日志文件及其轮换),则覆盖相关目的设置文件中的设置。

不要的

不要让 django 从文件中读取 DJANGO_SETTINGS_MODULE 设置。啊!想想这是多么元。如果您需要一个文件(如 docker env),在启动 django 进程之前将其读入环境。不要在您的项目/应用程序代码中覆盖 DJANGO_SETTINGS_MODULE,例如。基于主机名或进程名。如果您懒得设置环境变量(例如 setup.py 测试),请在运行项目代码之前在工具中进行设置。避免对 django 如何读取其设置进行魔术和修补,对设置进行预处理,但事后不要干预。没有基于复杂逻辑的废话。配置应该是固定的和物化的,而不是动态计算的。在这里提供一个备用默认值就足够了。你真的想调试吗,为什么在本地你有正确的设置集,但在远程服务器上的生产中,在一百台机器上,计算不同?哦!单元测试?对于设置?严重地?

解决方案

我的策略包括与 ini 样式文件一起使用的出色 django-environ,为本地开发提供 os.environment 默认值,一些最小且短的 settings/<purpose>.py 文件具有 import settings/base.py AFTER {3 } 是从 INI 文件设置的。这有效地给了我们一种设置注入。

这里的技巧是在导入 settings/base.py 之前修改 os.environment

要查看完整示例,请执行 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

设置/生产.py

对于生产,我们不应该期望一个环境文件,但是如果我们正在测试某些东西,那么拥有一个环境文件会更容易。但无论如何,我们只提供很少的内联默认值,因此 settings/base.py 可以做出相应的响应。

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

这里的主要兴趣点是 DEBUGASSETS_DEBUG 覆盖,仅当它们从环境和文件中丢失时,它们才会应用于 python os.environ

这些将是我们的生产默认值,无需将它们放在环境或文件中,但如果需要,它们可以被覆盖。整洁的!

设置/base.py

这些是您的主要香草 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 - 易于启动的本地默认值


嘿 Janusz ......所以在 .env 文件中将包含所有 API 密钥和身份验证密钥和密码等?就像 TWILLIO_API = "abc123" 一样?还是 TWILLIO_API = env("TWILLIO_API")?
是的,但这只是环境设置的后备。该文件对开发很方便,但不会保存在 repo 中或推送到生产环境中,您应该严格使用环境设置或您的平台等效项,这反过来会为服务器进程设置环境设置。
如何定义生产设置?例如,当我将我的 DJANGO_SETTINGS_MODULE 明确定义为网站/设置/生产时,初始化文件仍在加载 local.py 设置。我怎样才能避免它,或者我做错了什么? @JanuszSkonieczny
s
sobolevn

我在 django-split-settings 的帮助下管理我的配置。

它是默认设置的直接替代品。它很简单,但可配置。并且不需要重构您的现有设置。

这是一个小例子(文件 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-split-sttings 管理 django 设置的 blog post。看一看!


我试过了..一旦我尝试运行我的 django 单元测试就碰壁了..我只是不知道如何指定要读取的设置文件
我的代码中有 this 之类的东西,所以我检查了 settings.DEBUG 标志以了解我是否要导入东西.. 在 django 单元测试中该标志始终设置为 false(请参阅 here)所以我的解决方法是在每个测试中覆盖它们,例如 so
这是另一个问题:我的 uwsgi.ini 文件在 dev/prod 中有不同的设置。知道如何让它从我的设置文件中选择值吗?
对不起,我没有得到设置。您可以提出一个单独的问题,提供更多详细信息,我会尽力帮助您。
H
Harper Shelby

请记住,settings.py 是一个实时代码文件。假设您没有在生产环境中设置 DEBUG(这是最佳实践),您可以执行以下操作:

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

非常基本,但理论上,您可以仅根据 DEBUG 的值或您想要使用的任何其他变量或代码检查来达到任何复杂程度。


r
rewritten

大多数这些解决方案的问题在于,您要么在常用设置之前应用本地设置,要么在它们之后应用本地设置。

所以不可能覆盖像

特定于 env 的设置定义了 memcached 池的地址,在主设置文件中,该值用于配置缓存后端

特定于环境的设置将应用程序/中间件添加或删除到默认设置

同时。

一种解决方案可以使用带有 ConfigParser 类的“ini”样式的配置文件来实现。它支持多个文件、惰性字符串插值、默认值和许多其他好东西。一旦加载了多个文件,就可以加载更多文件,并且它们的值将覆盖以前的文件(如果有)。

您加载一个或多个配置文件,具体取决于机器地址、环境变量甚至之前加载的配置文件中的值。然后,您只需使用解析的值来填充设置。

我成功使用的一种策略是:

加载默认的 defaults.ini 文件

检查机器名称,并加载与反向 FQDN 匹配的所有文件,从最短匹配到最长匹配(所以,我加载了 net.ini,然后是 net.domain.ini,然后是 net.domain.webserver01.ini,每一个可能覆盖以前的值)。这个账号也是开发者的机器,所以每个人都可以设置自己喜欢的数据库驱动等进行本地开发

检查是否声明了“集群名称”,在这种情况下加载 cluster.cluster_name.ini,它可以定义数据库和缓存 IP 等内容

作为您可以通过此实现的示例,您可以为每个环境定义一个“子域”值,然后在默认设置(如 hostname: %(subdomain).whatever.net)中使用它来定义 django 需要工作的所有必要的主机名和 cookie .

这是我能得到的 DRY,大多数(现有)文件只有 3 或 4 个设置。除此之外,我必须管理客户配置,因此存在一组额外的配置文件(包括数据库名称、用户和密码、分配的子域等),每个客户一个或多个。

可以根据需要将其缩放到最低或最高,您只需在配置文件中放入要为每个环境配置的键,一旦需要新配置,将先前的值放入默认配置中,然后覆盖它在必要时。

该系统已被证明是可靠的,并且可以很好地与版本控制配合使用。长期以来,它一直用于管理两个独立的应用程序集群(每台机器 15 个或更多 django 站点的独立实例),拥有 50 多个客户,其中集群的大小和成员根据系统管理员的心情而变化。 .


您是否有一个如何将设置从 ini 加载到 Django 设置中的示例?
请参阅docs.python.org/2/library/configparser.html。您可以使用 config = ConfigParser.ConfigParser() 加载解析器,然后读取文件 config.read(array_of_filenames) 并使用 config.get(section, option) 获取值。所以首先你加载你的配置,然后你用它来读取设置的值。
R
Robert Kuzma

我也在与 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

也许这样的事情会帮助你。


M
Miguel Ventura

我对这个问题的解决方案也是这里已经说明的一些解决方案的混合:

我保留了一个名为 local_settings.py 的文件,该文件在 dev 中具有 USING_LOCAL = True 的内容,在 prod 中具有 USING_LOCAL = False 的内容

在 settings.py 我对该文件进行导入以获取 USING_LOCAL 设置

然后,我将所有与环境相关的设置都基于该设置:

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

我更喜欢拥有两个需要维护的单独的 settings.py 文件,因为与将它们分布在多个文件中相比,我可以更容易地将我的设置结构化在一个文件中。像这样,当我更新设置时,我不会忘记为两种环境都这样做。

当然,每种方法都有其缺点,这个也不例外。这里的问题是,每当我将更改推送到生产环境时,我都无法覆盖 local_settings.py 文件,这意味着我不能盲目地复制所有文件,但这是我可以忍受的。


d
dzida

对于我的大多数项目,我使用以下模式:

创建 settings_base.py 我存储所有环境通用的设置每当我需要使用具有特定要求的新环境时,我都会创建新的设置文件(例如 settings_local.py),它继承 settings_base.py 的内容并覆盖/添加适当的设置变量(来自 settings_base 导入 *)

(要使用自定义设置文件运行 manage.py,您只需使用 --settings 命令选项:manage.py <command> --settings=settings_you_wish_to_use.py


h
hundredrab

1 - 在您的应用程序中创建一个新文件夹并为其命名设置。

2 - 现在在其中创建一个新的 __init__.py 文件并在其中写入

from .base import *

try:
    from .local import *
except:
    pass

try:
    from .production import *
except:
    pass

- 在设置文件夹名称 local.pyproduction.pybase.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__)))

这样,项目目录可以结构化,并且可以在生产和本地开发之间进行管理。


s
stratosgear

我使用了上面提到的 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 文件,可以动态加载。


S
SudoKid

还有 Django 经典设置。我个人是它的忠实粉丝。它是由 Django IRC 上最活跃的人之一构建的。您将使用环境变量来设置内容。

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


M
Moinuddin Quadri

为了在不同的环境中使用不同的 settings 配置,请创建不同的设置文件。在您的部署脚本中,使用 --settings=<my-settings.py> 参数启动服务器,通过它您可以在不同的环境中使用不同的设置

使用这种方法的好处:

您的设置将根据每个环境模块化您可以导入包含基本配置的 master_settings.py 环境中的 environmnet_configuration.py 并覆盖您要在该环境中更改的值。如果您拥有庞大的团队,每个开发人员都可能拥有自己的 local_settings.py,他们可以将其添加到代码存储库中,而不会有任何修改服务器配置的风险。如果您使用 git,则可以将这些本地设置添加到 .gitnore;如果您使用 Mercurial 进行版本控制(或任何其他),则可以将这些本地设置添加到 .hginore。这样,本地设置甚至不会成为保持其清洁的实际代码库的一部分。


K
Kishor Pawar

我的设置拆分如下

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

我们有 3 个环境

开发者

分期

生产

现在显然分期和生产应该有尽可能多的相似环境。所以我们为两者保留了 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  

M
Mustapha-Belkacim

制作多个版本的 settings.py 是 12 Factor App methodology 的反模式。请改用 python-decoupledjango-environ


J
Joshua Partogi

我在 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)

我发现将设置文件分成两个单独的文件比在设置文件中执行大量 if 更容易。


s
sprksh

如果您愿意,作为维护不同文件的替代方法:如果您使用 git 或任何其他 VCS 将代码从本地推送到服务器,您可以做的是将设置文件添加到 .gitignore。

这将允许您在两个地方拥有不同的内容而不会出现任何问题。所以在服务器上你可以配置一个独立版本的 settings.py 并且在本地所做的任何更改都不会反映在服务器上,反之亦然。

此外,它还会从 github 中删除 settings.py 文件,这是我看到很多新手都在做的大错。


s
smrf

我认为@T 建议了最好的解决方案。 Stone,但我不知道为什么不在 Django 中使用 DEBUG 标志。我为我的网站编写以下代码:

if DEBUG:
    from .local_settings import *

简单的解决方案总是比复杂的解决方案好。


J
Jason Boyd

我发现这里的回答很有帮助。 (这个问题是否得到了更明确的解决?最后一个回复是一年前。)在考虑了所有列出的方法之后,我想出了一个我没有在此处列出的解决方案。

我的标准是:

一切都应该在源代码管理中。我不喜欢乱七八糟的东西。

理想情况下,将设置保存在一个文件中。如果我看的不正,我会忘记事情:)

无需手动编辑部署。应该能够使用单个结构命令进行测试/推送/部署。

避免将开发设置泄漏到生产中。

尽可能接近“标准”(*cough*) 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'

这样,应用程序默认为生产设置,这意味着您明确地将您的开发环境“列入白名单”。忘记在本地设置环境变量比忘记在生产环境中设置某些东西并使用一些开发设置要安全得多。

在本地开发时,无论是从 shell 还是在 .bash_profile 或任何地方:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(或者,如果您在 Windows 上进行开发,请通过控制面板或这些天所谓的任何东西进行设置……Windows 总是让它变得如此晦涩,以至于您可以设置环境变量。)

使用这种方法,开发设置都在一个(标准)位置,并在需要时简单地覆盖生产设置。任何与开发设置有关的乱七八糟的事情都应该完全安全地提交源代码控制,而不影响生产。


最好只维护不同的配置文件,并选择使用 DJango 标准环境变量 DJANGO_SETTINGS_MODULE