如果在settings.py
中未定义默认设置,那么在应用中处理默认设置的方式是什么?
我目前在应用中放置了一个default_settings
文件,我考虑了一些选项。我倾向于第一种选择,但在使用globals()
我经常看到应用程序在使用该设置的文件顶部执行FOO = getattr(settings, 'FOO', False)
但我认为如果值/名称很长,则此方法存在可读性/重复性问题。
1:将设置放在函数中并迭代locals / set globals
def setup_defaults():
FOO = 'bar'
for key, value in locals().items():
globals()[key] = getattr(settings, key, value)
setup_defaults()
优点:
缺点:
2:每次通话都写getattr(settings, 'MY_SETTING', default_settings.MY_SETTING)
优点: - 很清楚。
缺点: - 重复
3:始终将设置定义为FOO = getattr(settings, 'FOO', '...setting here...')
优点: - 始终覆盖默认值
缺点:
4:创建实用程序功能get_or_default(setting)
优点:
缺点:
5:创建设置类
class Settings(object):
FOO = 'bar'
def __init__(self):
# filter out the startswith('__') of
# self.__dict__.items() / compare to django.conf.settings?
my_settings = Settings()
缺点:
我很想听到反馈。
答案 0 :(得分:40)
我认为在您的应用包中创建settings.py
是很常见的,您可以在其中定义您的设置:
from django.conf import settings
FOO = getattr(settings, 'FOO', "default_value")
在您的应用中,您可以从应用的settings
模块中导入它们:
from myapp.settings import *
def print_foo():
print FOO
但我认为每个人都同意Django缺乏更好的通用架构!如果您正在寻找一种更复杂的方法来处理这个问题,那么有一些第三方应用程序就像django-appconf一样,但如果您想为您的应用程序引入另外一个依赖项,那么您的决定就是这样!
答案 1 :(得分:4)
这个怎么样?
在myapp / settings.py中:
from django.conf import settings
FOO = 'bar'
BAR = 'baz'
_g = globals()
for key, value in _g.items():
_g[key] = getattr(settings, key, value)
在myapp / other.py中:
import myapp.settings
print myapp.settings.FOO
由ncoghlan给出this answer,我觉得使用globals()就可以了。
答案 2 :(得分:4)
似乎我看到的每个解决方案都倾向于创建应用程序设置,代理,包装等内部副本。当设置为modified in run time like they do in tests时,这会让人感到困惑并产生问题。
对我来说,所有设置都属于django.conf.settings
,只有那里。您不应该从其他地方读取它们,也不应将其复制以供以后使用(因为它们可能会更改)。您应该设置一次,不要在以后对默认值进行打扰。
我理解在内部使用应用设置时放弃应用前缀的冲动,但这也是恕我直言的一个坏主意。遇到麻烦时,查找SOME_APP_FOO
不会产生结果,因为它在内部使用FOO
。混淆吧?为什么,几封信?还记得that explicit is better吗?
恕我直言,最好的方法是在Django自己的设置中设置这些默认值,为什么不使用已存在的管道?始终没有导入模块导入挂钩或劫持models.py
以初始化一些额外且复杂的元类管道。
为什么不使用AppConfig.ready来设置默认值?
class FooBarConfig(AppConfig):
name = 'foo_bar'
def ready(self):
from django.conf import settings
settings = settings._wrapped.__dict__
settings.setdefault('FOO_BAR_SETTING', 'whatever')
或者更好的是在一个单独的模块中以简洁的方式定义它们,并将它们导入为{或3}} {(3}}:
class FooBarConfig(AppConfig):
name = 'foo_bar'
def ready(self):
from . import app_settings as defaults
from django.conf import settings
for name in dir(defaults):
if name.isupper() and not hasattr(settings, name):
setattr(settings, name, getattr(defaults, name))
我不确定使用__dict__
是最佳解决方案,但您明白了,您始终可以使用hasattr
/ setattr
组合来获得效果。
这样您的应用设置就是:
django.conf.settings
中的设置方式 - 如果您愿意,可以实施一些名称转换PS。有一个Settings class,但它没有解释原因。所以我认为这一次,在初始化期间可能是一个合理的例外;)
PS2。请勿将单独的模块命名为settings
,因为从settings
导入django.conf
时,这可能会让您感到困惑。
答案 3 :(得分:1)
回应Phil Gyford的comment,暴露了测试中未被覆盖的设置问题(因为已经在模块中导入),我所做的是在{中定义__init__.py
类{1}}使用:
__init__
方法,将每个设置初始化为None
load
方法然后在代码中:
from . import AppSettings
def in_some_function():
some_setting = AppSettings.get_some_setting()
或者,如果您想一次性加载它们(但是测试中的覆盖设置不会对受影响的模块起作用):
from . import AppSettings
app_settings = AppSettings()
app_settings.load()
def in_some_function():
print(app_settings.some_setting)
然后,您可以在测试中使用override_settings
装饰器,并且仍然有一些干燥且清晰的方式来使用应用程序设置,但每次要获取设置时执行的指令都会更多(仅用于测试) ...)。
答案 4 :(得分:-1)
3号是最好的,因为它是最简单的。而且非常一致。
1号:很容易忽视它。如果我打开你的代码,我不会滚动到底部,我会想念它,我会认为在我自己的模块中不能覆盖这些设置。
数字2:不仅重复,因为它太长而难以阅读,而且默认值将被多次定义并分散在您的代码中。
4号:不一致的重复呼叫。
数字5:不一致,我们希望在不在类中的模块中定义设置。好吧,至少我确实希望找到被定义为模块,因为我已经看到许多使用方法3的应用程序,我使用它自己,所以我可能有偏见。