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


297

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

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

编辑:这个问题似乎没有标准答案,我已经接受了最受欢迎的方法。




2
公认的方法不再是最受欢迎的方法。
丹尼尔(Daniel)

2
django-split-settings非常易于使用。不需要重写任何默认设置。
sobolevn 2015年

您应该使用base.py文件,并在您的local.py“来自.base import *”中,和您在production.py中使用“ from .base import *”,您需要使用以下项目运行项目:python manage.py runserver- settings = project_name.settings.local
罗伯特·索利斯

Answers:


127

settings.py

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

您可以覆盖local_settings.py;中的需要;然后,它应该脱离版本控制。但是由于您提到了复制,我猜您没有使用;)


3
为了简化对新设置的跟踪/部署,请在生产/测试计算机上使用“ local_settings.py”,而在开发计算机上则不使用。
约翰·米

8
我就是这样做的-在settings.py的末尾添加这些行,以便它们可以覆盖默认设置
daonb 2010年

61
这种方法意味着您已经在开发和生产中运行了未版本化的代码。每个开发人员都有不同的代码库。我在这里称之为反模式。
pydanny

8
@pydanny问题是Django将其配置存储在.py文件中。您不能期望所有开发人员和生产服务器都使用相同的设置,因此您需要更改此.py文件或实施某些替代解决方案(.ini文件,环境等)。
Tupteq

3
我更喜欢调用模块settings_local,而不是将local_settings其与settings.py按字母顺序的文件夹列表分组。请settings_local.py使用版本控制了.gitignore作为凭证不属于Git的。想象一下,由于偶然而开放采购。我在git中保留了一个名为的模板文件settings_local.py.txt
换行

297

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.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上提供了一个示例项目布局模板


62
请注意--settings,您可以设置DJANGO_SETTINGS_MODULEenvvar ,而不是每次使用。例如,这在Heroku上很好用:将其全局设置为生产,然后在.env文件中用dev覆盖它。
Simon Weber

9
DJANGO_SETTINGS_MODULE谢谢Simon,这里最好使用env var。
kibibu 2013年

20
您可能需要将BASE_DIR设置更改为os.path.dirname(os.path.realpath(os.path.dirname(__file__) + "/.."))
Petr Peller,2013年

5
根据django文档,@ rsp导入from django.conf import settings,该对象是抽象化接口并使代码与设置位置doc.djangoproject.com/en/dev/topics/settings/…

3
如果通过环境变量设置DJANGO_SETTINGS_MODULE,我的wsgi.py文件中是否仍需要os.environ.setdefault(“ DJANGO_SETTINGS_MODULE”,“ projectname.settings.production”)?另外,我使用以下命令设置了环境变量:export DJANGO_SETTINGS_MODULE = projectname.settings.local,但是当我关闭终端时,它将丢失。我该怎么做才能确保它被保存?我应该将该行添加到bashrc文件中吗?
Kritz 2014年

71

代替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.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.pyprod.py或者dev.py,你可以覆盖任何东西__init__.py
  5. 这是简单易懂的python。没有重新导入的黑客。

2
我仍在尝试找出在project.wsgi和manage.py文件中为设置文件设置的内容。你会对此有所启示吗?具体来说,在我的manage.py文件中,我的os.environ.setdefault("DJANGO_SETTINGS_MODULE", "foobar.settings")foob​​ar是一个包含文件的__init__.py文件夹,而settings是一个__init__.py包含文件的文件夹,其中包含我的机密信息并导入dev.py,然后再导入common.py。 编辑没关系,我没有安装所需的模块。我的错!这很棒!!
teewuane 2014年

5
两件事:1)最好在dev.py中设置Debug = True,而不是prod.py中设置= False。2)使用DJANGO_SETTINGS_MODULE环境var进行切换,而不是在init .py中进行切换。这将有助于PAAS部署(例如Heroku)。
罗伯·格兰特

当我在django 1.8.4中使用此设置并尝试运行服务器时,我得到“ django.core.exceptions.ImproperlyConfigured:SECRET_KEY设置不得为空。”,甚至我的init .py文件中都包含SECRET_KEY 。我想念什么吗?
Polarcare

是不是更安全地使用类似AWS_SECRET_ACCESS_KEY = os.getenv(“ AWS_SECRET_ACCESS_KEY”)的东西?诚实的问题-我知道您为什么不希望对它进行版本控制,但是另一种选择是从环境中获取它。当然,哪个问题要解决设置环境变量的问题,但这可以留给您的部署机制,不是吗?
JL Peyret

20

我使用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的设置是一个实际的代码文件,这正是我所暗示的。我自己还没有做过这样的事情,但这绝对是比我的解决方案更好的解决方案。
哈珀·谢尔比

3
我只是第一次遇到这个问题,选择(成功!)使用您的解决方案,但有一点区别:我使用uuid.getnode()查找系统的uuid。所以我正在测试uuid.getnode()== 12345678901(实际上是一个不同的数字),而不是您使用的os.environ测试。我找不到文档来说服os.environ ['COMPUTERNAME']每台计算机都是唯一的。
乔·高尔顿

os.environ ['COMPUTERNAME']在Amazon AWS Ubuntu上不起作用。我收到一个KeyError。
nu Everest 2014年

在使用UUID时,已证明该解决方案对我而言是最佳和最简单的。它不需要很多复杂和过度模块化的拼凑。在生产环境中,您仍然需要将数据库密码和SECRET_KEY放置在版本控制之外的单独文件中。
nu everest 2014年

os.environ['COMPUTERNAME']不幸的是在PythonAnywhere上不起作用。您收到一个KeyError。
nbeuchat

14

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

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


2
本地开发服务器又如何呢?有没有办法告诉django网络服务器(使用运行python manage.py runserver),要使用哪个设置文件?
akv

2
@akv如果在运行服务器命令的末尾添加--settings = [模块名称](无.py扩展名),则可以指定要使用的设置文件。如果要这样做,请帮自己一个忙,并在配置了开发设置的情况下制作一个shell脚本/批处理文件。相信我,你的手指会感谢你的。
T. Stone,

这是我使用的解决方案。破解用于生产或开发的设置文件是很麻烦的
George Godik 09年

4
我认为最好在开发中使用settings.py,因为您不必一直指定它。
安德烈·博萨德

我是否假设此方法需要通过代理django.conf.settings导入设置模块,对吗?否则,当进行实时推送时,您需要编辑导入声明以指向正确的设置文件。
Groady 2011年

8

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


仅考虑所有这些相互交织的文件,就让我头疼。合并,导入(有时是有条件的),覆盖,修补已设置的内容,以防DEBUG稍后设置更改。什么样的恶梦!

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

我希望我最终能通过以下解决方法达到(我的)最佳解决方案。

让我们回顾一下目标(一些普通的,一些我的)

  1. 保守秘密-不要将其存储在仓库中!

  2. 通过环境设置(12因子样式)设置/读取密钥和机密。

  3. 具有合理的后备默认设置。理想情况下,对于本地开发,除默认值外,您不需要任何其他内容。

  4. …但请尝试确保默认生产的安全。最好不要在本地错过设置替代,而不必记住要调整默认设置以确保生产安全。

  5. 能够以DEBUG可能影响其他设置的方式打开/关闭(例如,是否使用javascript压缩)。

  6. 在目标设置(例如本地/测试/过渡/生产)之间切换时,仅应基于,而仅此DJANGO_SETTINGS_MODULE而已。

  7. …但是可以通过环境设置(例如)进行进一步的参数设置DATABASE_URL

  8. …还允许他们使用不同的用途设置,并在本地并排运行它们,例如 在本地开发人员机器上进行生产设置,以访问生产数据库或对压缩样式表进行烟雾测试。

  9. 如果未明确设置环境变量(至少需要一个空值),则失败,例如在生产中尤其如此。EMAIL_HOST_PASSWORD

  10. DJANGO_SETTINGS_MODULEdjango-admin startproject期间响应manage.py中的默认设置

  11. 条件语句保持到最低限度,如果条件旨意环境类型(例如,用于生产一系列的日志文件,它的自转),在相关的旨意设置文件中的设置优先。

  1. 不要让django从文件中读取DJANGO_SETTINGS_MODULE设置。
    啊! 想想这是元数据。如果您需要一个文件(例如docker env),请在启动django进程之前将其读入环境。

  2. 不要在您的项目/应用代码中覆盖DJANGO_SETTINGS_MODULE,例如。基于主机名或进程名。
    如果您懒于设置环境变量(例如setup.py test),请在运行项目代码之前在工具中进行设置。

  3. 避免使用django读取其设置的魔术和修补程序,对设置进行预处理,但之后不要干预。

  4. 没有复杂的基于逻辑的废话。配置应该是固定的,不能实时计算。提供备用默认值仅是这里的逻辑。
    您是否真的要调试,为什么要在本地设置正确的设置集,而在远程服务器上的生产环境中(在一台一百台计算机上)计算的结果却有所不同?哦! 单元测试?进行设定?认真吗

我的策略是由优秀的Django的ENVIRON与使用的ini样式文件,提供os.environment当地发展的默认设置,一些最起码的,短settings/<purpose>.py的是有一个文件 import settings/base.py os.environment是从一个设置INI文件。这有效地为我们提供了一种设置注入。

这里的窍门是os.environment在导入之前进行修改settings/base.py

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

settings / production.py

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

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

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

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

设置/ 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,甚至可以由环境设置覆盖!好极了!

实际上,我们具有不同的重要性等级:

  1. settings / .py-根据目的设置默认值,不存储秘密
  2. settings / base.py-主要由环境控制
  3. 过程环境设置-12要素宝贝!
  4. settings / .env-本地默认设置,易于启动

嘿Janusz ...所以在.env文件中将放所有API密钥,身份验证密钥和密码等?就像TWILLIO_API =“ abc123”一样?还是TWILLIO_API = env(“ TWILLIO_API”)?
dbinott

是的,但这只是环境设置的后备。该文件非常便于开发,但不会保存在存储库中或推送到生产环境中,在此环境中,您应严格使用环境设置或等效的平台,这些设置又将为服务器进程设置环境设置。
Janusz Skonieczny

7

我在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设置django-split-sttings。看一看!


1
我试过了..一旦尝试运行django单元测试,就碰到了墙..我只是不知道如何指定要读取哪个设置文件
abbood

我为您创建了一个摘要
sobolevn

我得到的东西像这样在我的代码,所以我检查settings.DEBUG标志知道如果我想进口的东西..那标志始终设置为false在Django单元测试(见这里),所以我的解决办法是在覆盖它们像这样的
Abbood

这是另一个问题:我的uwsgi.ini文件在dev / prod中有不同的设置。任何关于如何使其从我的设置文件中选择值的想法吗?
2013年

抱歉,我没有安装程序。您可以问一个单独的问题,提供更多详细信息,我会尽力帮助您。
sobolevn

6

这些解决方案中的大多数问题是您在本地设置之前之后应用了本地设置。

因此,不可能覆盖诸如

  • 特定于环境的设置定义了内存缓存池的地址,在主设置文件中,此值用于配置缓存后端
  • 特定于环境的设置将应用程序/中间件添加或删除为默认设置

与此同时。

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

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

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

  • 加载默认defaults.ini文件
  • 检查机器名称,并加载与反向FQDN匹配的所有文件,从最短匹配到最长匹配(因此,我先加载net.ini,然后加载,然后net.domain.ini再加载net.domain.webserver01.ini,每个可能覆盖前一个值)。此帐户也用于开发人员的计算机,因此每个人都可以设置其首选的数据库驱动程序等以进行本地开发
  • 检查是否声明了“集群名称”,在这种情况下cluster.cluster_name.ini,请检查load ,它可以定义数据库和缓存IP之类的内容

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

这是我可以得到的DRY,大多数(现有)文件只有3或4个设置。最重要的是,我必须管理客户配置,因此存在另外一组配置文件(带有数据库名称,用户和密码,分配的子域等),每个客户一个或多个。

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

该系统已经证明是可靠的,并且可以与版本控制一起很好地工作。它已长期用于管理两个单独的应用程序集群(每台机器15个或更多django站点的单独实例),拥有50多个客户,这些集群根据sysadmin的心情来改变大小和成员。 。


1
您是否有一个示例,说明如何将ini中的设置加载到Django的设置中?
kaleissin

请参阅docs.python.org/2/library/configparser.html。您可以加载解析器,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

我对这个问题的解决方案在某种程度上也是这里已经提到的一些解决方案的混合:

  • 我保留了一个名为dev和prod中local_settings.py内容的文件USING_LOCAL = TrueUSING_LOCAL = False
  • 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

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

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

from .base import *

try:
    from .local import *
except:
    pass

try:
    from .production import *
except:
    pass

3 -创建在设置三个新文件夹的名称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__)))

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


2

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

使用这种方法的好处

  1. 您的设置将根据每个环境进行模块化

  2. 您可以在中导入master_settings.py包含基本配置的内容,environmnet_configuration.py并覆盖要在该环境中更改的值。

  3. 如果您有庞大的团队,则每个开发人员可能都有自己的团队,可以将其local_settings.py添加到代码存储库中,而无需修改服务器配置。您可以添加这些本地设置,.gitnore如果您使用的git或者.hginore,如果你的Mercurial版本控制(或任何其他)。这样,本地设置甚至不会成为保持干净的实际代码库的一部分。


2

我的设置如下拆分

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

我们有3个环境

  • 开发者
  • 分期
  • 生产

现在显然,登台和生产应该具有最大可能的相似环境。所以我们都坚持prod.py

但是在某些情况下,我不得不确定正在运行的服务器是生产服务器。@T。斯通的答案帮助我写了以下支票。

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,对本地所做的任何更改都不会反映在服务器上,反之亦然。

另外,它还会从github上删除settings.py文件,这是一个很大的错误,我看到很多新手都在这样做。



0

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

if DEBUG:
    from .local_settings import *

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


-2

我发现这里的回复非常有帮助。(是否已更明确地解决了此问题?上次答复是一年前。)在考虑了列出的所有方法之后,我想出了一个我未在此处列出的解决方案。

我的标准是:

  • 一切都应该在源代码控制中。我不喜欢随便摆姿势。
  • 理想情况下,将设置保存在一个文件中。如果我没看对的话我会忘记的:)
  • 无需手动编辑即可部署。应该能够使用单个结构命令进行测试/推送/部署。
  • 避免将开发设置泄漏到生产中。
  • 保持尽可能接近“标准”(*咳嗽*)Django布局。

我以为打开主机是有道理的,但后来发现这里的真正问题是针对不同环境的不同设置,并且花了很多时间。我把这个代码在结束我的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'

这样,该应用程序默认为生产设置,这意味着您将开发环境明确“列入白名单”。与在相反的情况下忘记在本地设置环境变量相比,如果忘记在生产环境中设置某些内容并使用某些开发设置,则要安全得多。

从外壳或.bash_profile或任何地方进行本地开发时:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(或者,如果您是在Windows上进行开发,则可以通过“控制面板”或目前称为“控制面板”的工具进行设置。Windows总是使它晦涩难懂,因此您可以设置环境变量。)

使用这种方法,开发人员设置全部集中在一个(标准)位置,并在需要时仅覆盖生产设置。任何与开发设置有关的更改都应该完全安全地进行源代码控制,而不会影响生产。


最好只是维护不同的配置文件,然后使用DJango标准环境变量DJANGO_SETTINGS_MODULE进行选择
Rob Grant
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.