Django本地设置


75

我正在尝试在Django 1.2中使用local_setting ,但对我来说不起作用。目前,我只是将local_settings.py添加到我的项目中。

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco1',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

local_settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco2',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

问题在于local_settings.py不会覆盖settings.py。怎么了?


2
在我阅读此问题时,有三个非常不同且都很有趣的答案。我对Daniel的解决方案的评论感到困惑。在我看来,似乎没有万能的解决方案。Daniel的解决方案简单有效。jano的解决方案以某种方式更清洁,只有在已经干净的环境中才有意义,而且成本低廉。John的解决方案在某种程度上更重,但在最受限制的环境中却很有趣。总而言之,只需选择适合您的用例的最简单的即可。
斯特凡纳·古里科

Answers:


138

您不仅可以添加local_settings.py,还必须显式导入它。

最后一刻你的settings.py的,补充一点:

try:
    from local_settings import *
except ImportError:
    pass

try / except块在那里,因此当您实际上尚未定义local_settings文件时,Python只会忽略这种情况。


3
是的,grep -r "local_setting" django几乎可以保证这不是“开箱即用”的行为
Yuji'Tomita'Tomita

8
这种方法意味着您在每个位置都运行了未版本化的代码,这是一种反模式。
pydanny

2
@pydanny您建议使用什么替代方法?
布罗德尼2013年

1
@pydanny-该答案明确表示,local_settings.py (or more commonly prod_settings.py) is NOT in version control, and used in production by specifying --settings=prod_settings or similar.因此似乎未版本化的代码仍在每个位置运行。不是吗?
约瑟夫

1
传递异常是一个非常糟糕的主意。如果local_settings.py仅存在语法错误,则不会导入该错误,并且您可能会使用意外的settings.py中的默认设置运行。例如,如果settings.py连接到生产数据库。最好总是需要一个local_settings.py并抛出错误(如果找不到)。
马特

82

我认为这是最佳做法:

  • local_settings 从进口 settings
  • local_settings覆盖设置具体到当地的环境,尤其是DATABASESSECRET_KEYALLOWED_HOSTSDEBUG变量
  • 传递给Django管理命令标志 --settings=local_settings

您可以这样实现local_settings

from settings import *

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco2',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

一些其他要点:

  • settings.py 处于版本控制中,编写方式使得贡献者可以随时使用
  • local_settings.py(或更常见的prod_settings.py是)不在版本控制中,而是通过指定--settings=prod_settings或类似方式在生产中使用。

尽可能少地触摸库存设置文件也可以更轻松地升级Django版本。当您将Django升级到下一个版本时,请查看库存settings.py与您的库存之间的差异,并根据更改内容采取必要的措施。默认值的更改可能很重要,并且您触摸原始settings.py文件的次数越少,越容易识别上游更改。


2
我喜欢这种方法。尽可能少地触摸空的设置文件,可以在升级Django版本时更轻松地正确配置新设置。
m000

3
这应该是被接受的答案,请阅读被接受的答案中的注释,理由是该注释存在问题(“在每个位置运行的未转换代码”)。
eggonlegs 2014年

6
我看不出这与接受的答案有何不同。此local_settings也不应版本化。如果是这样,开发人员可能会意外更改生产计算机上的local_settings。
GergelyPolonkai 2014年


1
@azmeuk上下文很重要。import *通常不好,但是当它是文件中唯一的导入时,完全可以接受。它应该是在local_settings.py
janos

11

由于主题经常出现,因此让我总结一下为什么要考虑这种方法:

  • 笨拙的设置文件非常快速且易于更改;特别是在生产环境中。无需python:任何白痴都可以进入并更改仅列出名称和值的文件中的数据库密码;特别是与复杂的python设置文件相比,该文件充满了神秘的危险BIGCAPS名称。

  • 应用程序settings应与应用程序完全分开code。您可以将config.ini放置在存储库根目录之外,而不必再担心回购请求会破坏您的设置,或者您的个人设置会污染该回购协议,或者您的设置中的代码很聪明。 。

这不适用于小型项目,但是在大型项目中,我得出的结论是local_settings策略只是不切实际;随着时间的流逝,足够多的应用程序编程变得难以处理。主要是因为设置变得派生和/或相互依赖。有充分的理由可以使设置根据本地设置做出反应,从而迫使local_settings文件的导入逐渐向中间倾斜settings.py。我发现事情开始变得一团糟。

我当前的解决方案是使用config文件,我将其复制为“ local.ini”。它仅包含在部署的实例之间实际发生更改的那些值。没有代码:它们只是值和布尔值:

[global]
domain = 127.0.0.1:8000
database_host = 127.0.0.1
database_name = test_database
debug = Yes
google_analytics_id = UA-DEV-1
payments = testing
use_cdn = No

有了这个,我可以settings.py像对待其他任何应用程序代码一样对待它:对其进行调整,检入并部署,而不必担心针对local_settings python代码中潜伏的任何代码进行测试。我settings.py是自由的是拿出当后来设置取决于本地设置比赛条件,我可以打开和关闭编写易于后续线性码开关的功能。当我忘记添加一些新值时,就不再急着调整local_settings文件了,也没有更多的东西daves_local_settings.pybobs_local_settings.py文件正在进入存储库。

from ConfigParser import RawConfigParser
parser = RawConfigParser()

APPLICATION_ROOT = path.abspath(path.dirname(__file__))
parser.readfp(open(path.join(APPLICATION_ROOT, 'local.ini')))

# simple variables
DATABASE_HOST = parser.get('global', 'database_host')
DATABASE_NAME = parser.get('global', 'database_name')

# interdependencies
from version import get_cdn_version
CDN = 'd99phdomw5k72k.cloudfront.net'
if parser.getboolean('global', 'use_cdn'):
    STATIC_URL = '/{}/static/{}/'.format(CDN, get_cdn_version())
else:
    STATIC_URL = '/static/'


# switches
payments = parser.get('global', 'payments')
if payments == 'testing':
    PAYMENT_GATEWAY_ENDPOINT = 'https://api.sandbox.gateway.com'
else:
    PAYMENT_GATEWAY_ENDPOINT = 'https://api.live.gateway.com'

如果遇到BOFH(就像我一次遇到的那样),他将能够将BOOTH粘贴local.ini/etc目录中,/etc/ourapp.ini并因此将应用程序目录本身保持为纯存储库导出,这一点使他特别兴奋。当然,您可以使用local_settings.py进行此操作,但他最后要做的就是弄乱python代码。他可以处理的简单配置文件。


是什么让您想要使用不同于常规Python文件的其他语法(并且需要解析器)?这就是我们命名空间的原因。
Joost

因为aregular Python file将被执行,而配置文件是非常简单的傻瓜设置集合;没有诱惑让它去做“聪明”的事情,任何白痴(例如,非Python的人,或者12个月后的你自己)都可以研究出如何更新基本设置,而不必担心会破坏一切。
John Mee 2015年

语法实际上是相同的。我想这是偏爱的问题。
Joost,2015年

1
就像我说的那样,小型项目没有什么回报。但是一旦settings.py超过50行,或者该行import local_settings.py不再位于最底部,您就会看到更多价值。
John Mee 2015年

对我来说,最糟糕的部分是您需要为每个设置值编写代码。而且,如果您只是将所有内容导入文件,则需要将其他变量从字符串转换为变量。另外,我喜欢串联。我的配置中也有很多列表和字典。
kagronick

9

我保留了__local_settings.py

  • local_settings.py 在版本控制中被忽略,但不是 __local_settings.py
  • 更新README.md以通知团队如何设置:(cp {__,}local_settings.py为他们的local_settings复制一份)

以往

我曾经导入那些设置。

# settings.py
DATABASE = {...}

try:
    from .local_settings import *
except ImportError:
    pass

现在

我只是从中导入设置本身local_settings.py

并用下面的命令:python manage.py runserver --settings=<proj>.local_settings

# local_settings.py & __local_settings.py
from .settings import *

DATABASE = {...}

而且由于我通常不manage.py直接与之交互,因为某些参数对我来说是明确必需的(例如address:port)。因此,我将所有这些命令都放入了自己的Makefile

例如,这是我的Makefile:

run:
    python manage.py runserver 0.0.0.0:8000 --settings=<proj>.local_settings

sh:
    python manage.py shell_plus --settings=<proj>.local_settings

dep:
    npm install
    pip install -r requirements.txt

从而:

make dep
make sh 
make run

结论

如果您将其Makefile用作工作流,则可以使用较早的方法,但是如果您使用的是makefile,那么我认为最好在Makefile中更明确。


Makefile只是一个想法和意见。尝试使用较早的方法总体上可能会更好
Yeo

6

在运行服务器之前

export DJANGO_SETTINGS_MODULE=your_app_name.local_settings 其中your_app_name应该用您的应用名称替换。而且不要忘记做

from settings import *

在您的local_settings.py文件中


2
您应该从该行中省略.py,(不要忘了用实际的应用程序替换appname)
johanvdw

4

另一种方法是使用python-dotenv和环境变量来定制不同环境的设置。

.env您的旁边创建文件settings.py

# .env
SECRET_KEY=your-secret-key
DATABASE_PASSWORD=your-database-password

将以下代码添加到您的settings.py

# settings.py
from dotenv import load_dotenv
load_dotenv()

# OR, explicitly providing path to '.env'
from pathlib import Path  # python 3.4+
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

此时,从.env文件中解析的键/值将作为环境变量出现,可以通过以下方式方便地访问它们os.getenv()

# settings.py
import os
SECRET_KEY = os.getenv('SECRET_KEY')
DATABASE_PASSWORD = os.getenv('DATABASE_PASSWORD')   

1

我找到了类似的解决方案。这是我在这种情况下的配置:

settings.py:

DEBUG = False

try:
    from local_settings import *

except ImportError:
    pass

if DEBUG is False:
    ALLOWED_HOSTS = ['sth.com']
    DATABASES = {
        ....
    }

local_settings.py:

from settings import *
ALLOWED_HOSTS = ['*']
DEBUG = True
DATABASES = {
    ...
}

1

将此添加到文件settings.py的末尾

try:
    from .local_settings import *
except ImportError:
    pass

并使用您的新设置创建文件local_settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'banco2',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': '123',                  # Not used with sqlite3.
        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}
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.