如何配置Django以便进行简单的开发和部署?

117

我在进行Django开发时,倾向于使用SQLite,但在生产服务器上通常需要更强大的解决方案(比如MySQL/PostgreSQL等)。

不可避免地,还需要对Django设置进行其他更改:不同的日志记录位置/强度,媒体路径等。

那么,如何管理所有这些变化以使部署过程简单、自动化呢?


我似乎没有其他人那么高端 :). 我只是利用 Django 提供的 ORM。 - Andrew Sledge
1
问题是如何自动化更改设置以在不同环境之间切换 :-) - Guruprasad
3
请参见 https://code.djangoproject.com/wiki/SplitSettings。 - John Mee
你可以看一下这个包:django-split-settings - sobolevn
15个回答

86
更新:已发布django-configurations,对大多数人来说,这可能比手动操作更好。
如果您更喜欢手动操作,可以使用我之前的答案:
我有多个设置文件。
- settings_local.py - 主机特定配置,例如数据库名称、文件路径等。 - settings_development.py - 用于开发的配置,例如DEBUG = True。 - settings_production.py - 用于生产的配置,例如SERVER_EMAIL。
我通过一个settings.py文件将它们全部绑定在一起,首先导入settings_local.py,然后导入其他两个文件中的一个。它通过settings_local.py中的两个设置DEVELOPMENT_HOSTS和PRODUCTION_HOSTS决定加载哪个。settings.py调用platform.node()查找运行的主机名,然后在列表中查找该主机名,并根据找到的列表加载第二个设置文件。
这样,您真正需要担心的就是使settings_local.py文件保持最新的特定于主机的配置,其他所有内容都会自动处理。
在此处查看示例


2
如果开发环境和生产环境在同一台机器上怎么办?platform.node()返回的也是相同的。 - gwaramadze
3
示例链接已失效。 - Jickson
基于主机列表确定设置的想法很好!我有一个小问题是命名方式(settings_local.py总是被首先导入,因此任何未被覆盖的设置实际上仍然在生产中使用,使后缀“_local”相当令人困惑),而且您没有使用模块(settings/base.py、settings/local.py和settings/production.py)。最好将其保留在单独的存储库中...更好的做法是使用安全服务从规范化的资源(对于大多数人可能过度)中提供此信息,这样新主机就不需要发布新版本。 - DylanYoung
更好的是,如果您使用机器管理软件,而不是在.py文件中检查主机列表,从而使每个主机都可以访问有关其他每个主机配置的信息,您可以将manage.py模板化为在部署配置中使用适当的设置文件。 - DylanYoung

26

就我个人而言,我会为项目使用一个单独的settings.py文件,然后让它查找当前所在主机的主机名(我的开发机器的主机名以“gabriel”开头,所以我只需要这样写:

import socket
if socket.gethostname().startswith('gabriel'):
    LIVEHOST = False
else: 
    LIVEHOST = True

其它部分中我有类似以下内容:

if LIVEHOST:
    DEBUG = False
    PREPEND_WWW = True
    MEDIA_URL = 'http://static1.grsites.com/'
else:
    DEBUG = True
    PREPEND_WWW = False
    MEDIA_URL = 'http://localhost:8000/static/'

等等。可读性稍差一些,但它能正常工作并避免了同时管理多个设置文件的烦恼。


我喜欢这个想法,但它不能让我区分在同一主机上运行的不同Django实例。例如,如果您在同一主机上为不同的子域运行不同的实例,则会发生这种情况。 - Erik

25

在settings.py的结尾处,我有以下内容:

try:
    from settings_local import *
except ImportError:
    pass

这样,如果我想要覆盖默认设置,我只需要将settings_local.py放在settings.py旁边。


4
这有一定危险性,因为如果在settings_local中有错别字导致了ImportError,那么这个except语句会悄无声息地将其吞掉。 - Chris Martin
你可以检查消息 No module named...cannot import name...,但这种方法很脆弱。或者,将你的导入放在 settings_local.py 中的 try 块中,并引发一个更具体的异常:MisconfiguredSettings 或类似的异常。 - DylanYoung
在最新版本的Python中,您可以使用except ModuleNotFoundError - warvariuc

11

我有两个文件。 settings_base.py 包含常见/默认设置,并已检入源代码控制系统。每次部署都有单独的 settings.py,它在开头执行 from settings_base import *,然后根据需要进行覆盖。


1
我也使用这个。它比相反的方式更优越(即在settings.py末尾使用dmishe的“from settings_local import *”),因为如果需要,它允许本地设置访问和修改全局设置。 - Carl Meyer
3
如果 settings_local.py 中使用了 from settings import *,那么它可以覆盖 settings.py 中的值(要在 settings.py 的末尾导入 settings_local.py 文件)。 - Seth
那样做是可以的。请查看上面的https://dev59.com/vnVD5IYBdhLWcg3wGXlI#7047633。 @ Seth那是一个循环导入的方法。 - DylanYoung

7
我发现最简单的方法是:
1)在本地开发时使用默认的 settings.py,并且 2)创建一个以以下内容开始的production-settings.py文件:
import os
from settings import *

然后只需覆盖在生产环境中不同的设置:

DEBUG = False
TEMPLATE_DEBUG = DEBUG


DATABASES = {
    'default': {
           ....
    }
}

Django 怎么知道要加载 production-settings? - AlxVallejo

2

与此有些相关的是,如果你需要使用多个数据库部署Django本身,你可以看一下Djangostack。你可以下载一个完全免费的安装程序,它允许你安装Apache、Python、Django等等。在安装过程中,我们允许你选择要使用哪个数据库(MySQL、SQLite、PostgreSQL)。我们在内部自动化部署时广泛使用这些安装程序(它们可以以无人值守模式运行)。


1
另外,我想推荐Django Turnkey Linux,它基于Ubuntu *NIX堆栈,并预装了Django。 - jochem

1

嗯,我使用这个配置:

在settings.py的末尾:

#settings.py
try:
    from locale_settings import *
except ImportError:
    pass

而在 locale_settings.py 文件中:

#locale_settings.py
class Settings(object):

    def __init__(self):
        import settings
        self.settings = settings

    def __getattr__(self, name):
        return getattr(self.settings, name)

settings = Settings()

INSTALLED_APPS = settings.INSTALLED_APPS + (
    'gunicorn',)

# Delete duplicate settings maybe not needed, but I prefer to do it.
del settings
del Settings

1
很多复杂的答案!
每个settings.py文件都带有:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

我使用该目录来设置DEBUG变量,如下所示(将其替换为您的开发代码所在的目录):

DEBUG=False
if(BASE_DIR=="/path/to/my/dev/dir"):
    DEBUG = True

然后,每次移动settings.py文件时,DEBUG将变为False,这就是您的生产环境。
每当您需要与开发环境中不同的设置时,只需使用:
if(DEBUG):
    #Debug setting
else:
    #Release setting

1

为什么要把事情搞得这么复杂?我从PHP/Laravel背景转入Django。 我使用.env,你可以轻松配置它。

安装这个包

django-environ

现在,在包含settings.py的文件夹中,创建一个.env文件(确保将此文件放入gitignore)。
.env文件中,放置环境变量,如调试设置状态、密钥、邮件凭据等。
示例.env的快照。
SECRET_KEY="django-insecure-zy%)s5$=aql=#ox54lzfjyyx!&uv1-q0kp^54p(^251&_df75i"

DB_NAME=bugfree
DB_USER=postgres
DB_PASSWORD=koushik
DB_PORT=5433
DB_HOST=localhost

APP_DEBUG=True # everything is string here

在设置中,确保使用此方法实例化它。
import environ
env = environ.Env()
environ.Env.read_env()

现在您可以从.env文件中导入值并将它们放在任何您想要的地方。在settings.py中有一些示例。
SECRET_KEY = env('SECRET_KEY')
DEBUG = bool(env('APP_DEBUG', False))

您也可以像这样设置默认值:

env('DB_NAME', 'default value here')

提示 您可以在与.env文件相同的文件夹中创建另一个.env.example文件,以便您可以拥有.env的模板,并且您可以提交.example文件。这有助于未来的开发人员轻松地了解有哪些环境变量。 .env.example应该是这样的

SECRET_KEY=VALUE_HERE

DB_NAME=VALUE_HERE
DB_USER=VALUE_HERE
DB_PASSWORD=VALUE_HERE
DB_PORT=VALUE_HERE
DB_HOST=VALUE_HERE

EMAIL_HOST=VALUE_HERE
EMAIL_PORT=VALUE_HERE
EMAIL_HOST_USER=VALUE_HERE
EMAIL_HOST_PASSWORD=VALUE_HERE
DEFAULT_FROM_EMAIL=VALUE_HERE

1

我将我的settings.py文件放在外部目录中。这样,它就不会被检入源代码控制,也不会被部署覆盖。我将以下内容放在Django项目的settings.py文件中,以及任何默认设置:

import sys
import os.path

def _load_settings(path):    
    print "Loading configuration from %s" % (path)
    if os.path.exists(path):
    settings = {}
    # execfile can't modify globals directly, so we will load them manually
    execfile(path, globals(), settings)
    for setting in settings:
        globals()[setting] = settings[setting]

_load_settings("/usr/local/conf/local_settings.py")

注意:如果您不能信任local_settings.py文件,这将非常危险。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接