0

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

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

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

BAR = some_value
FOO = some_function(BAR)

然而,有很多设置文件是很流行的,每个环境都有一个(例如生产、开发、测试、阶段等),正如“Django 的两个勺子:Django 1.5 的最佳实践”一书中的项目布局中所建议的那样.

在这种情况下,有一个settings.base模块,它的所有内容由settings.dev,settings.prod等导入,它们添加自己的特定值或覆盖在settings.base.

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

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

想法?

4

2 回答 2

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.settingsBAR未定义时,这不会处理(边缘)情况。

于 2013-08-03T21:04:04.510 回答
0

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

大多数人已经这样做来构建模板路径设置。

Django模板路径

现在让我们想象一下:

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

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

DYNAMIC_SETTING = ref.get(ENV.lower(), None)  # => 'BAZ'
于 2013-08-02T22:19:05.290 回答