在Django中,是否可以基于另一个定义动态计算的设置?

时间:2013-08-02 20:44:51

标签: python django settings

(也许这个问题更多的是关于Python,但Django是上下文,所以在这里)

假设您需要一个设置FOO,其值取决于设置BAR的值(最简单的情况是使CELERY_RESULT_BACKEND等于BROKER_URL)。

如果您只有一个设置文件,那么很容易实现:

BAR = some_value
FOO = some_function(BAR)

然而,拥有许多设置文件非常受欢迎,每个环境都有一个(例如制作,开发,测试,舞台等),正如书中的project layout所提出的那样,“Django的两个Scoops: Django 1.5“的最佳实践。

在这种情况下,有一个settings.base模块,其中包含settings.devsettings.prod等所有内容,它们会添加自己的特定值或覆盖settings.base中定义的值。 {1}}。

当我想在某些模块中覆盖BAR时会出现问题,但我必须记得每次重写后重新计算FOO。这很容易出错,而不是干。

lambda函数不起作用,因为该设置是可调用的,而不是结果值。内置函数/装饰器property将是理想的,但它只能在类(新式)中使用。我什么都不知道。

想法?

2 个答案:

答案 0 :(得分:0)

是的,设置文件也只是一个python脚本。

大多数人都已经建立了模板路径设置。

Django template Path

现在让我们想象一下:

ref = {
    'dev':  'FOO',
    'qa':   'BAR'
    'prod': 'BAZ'
}

ENV = 'PROD'  # Can also be DEV or QA

DYNAMIC_SETTING = ref.get(ENV.lower(), None)  # => 'BAZ'

答案 1 :(得分:0)

稍微讨厌:

class DynamicWrapper(object):
    _initialized = False

    def __init__(self, wrapped_name)
        self._wrapped = wrapped_name

    def __get__(self):
        if not self._initialized:
            self._initialized = True
            return self
        if not hasattr(self, '_computed_val'):
            from django.conf import settings
            val = getattr(settings, self._wrapped)
            self._computed_val = some_func(val)
        return self._computed_val

BAR = 'some_value'
FOO = DynamicWrapper('BAR')

这个想法如下:

  • Django的设置对象在初始化设置对象时使用getattr(settings_module, setting)一次(请注意,当您执行from django.conf import settings实际导入对象而不是模块时)。结果设置为设置对象的属性。调用__get__,返回self,因此settings.FOODynamicWrapper实例。
  • 访问settings.FOO时,这将在__get__对象上再次调用DynamicWrapper,这是您希望它返回实际值的时间。该值根据some_func计算,并返回值而不是DynamicWrapper对象。
  • 任何后续尝试获取settings.FOO的值也会调用__get__方法,但这次计算出的值缓存为self._computed_val并立即返回。

如果有多个Settings个对象,当FOO以不同于django.conf.settings的方式访问BAR或{{1}}时,这不会处理(边缘)情况没有定义的。