Django可插拔应用程序的默认设置约定?

Yuj*_*ita 30 python django configuration

如果未定义应用程序中的默认设置,那么处理默认设置的dangangonautic方法是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()
Run Code Online (Sandbox Code Playgroud)

优点:

  • 只需要写一次var名称来从django设置中提取相同名称的默认值.

缺点:

  • 不习惯使用globals()并且不知道任何含义

2:写下getattr(settings, 'MY_SETTING', default_settings.MY_SETTING)每个电话

优点: - 非常清楚.

缺点: - 重复


3:始终将设置定义为 FOO = getattr(settings, 'FOO', '...setting here...')

优点: - 始终覆盖默认值

缺点:

  • 重复(必须定义var两次 - 一次是字符串形式,一次是var)
  • 设置不是可读的,因为它现在是第三个参数

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()
Run Code Online (Sandbox Code Playgroud)

缺点:

  • 不能从foo.bar.my_settings导入FOO(实际上,这是一个可怕的交易破坏者!)

我很乐意听到反馈.

Ber*_*ant 42

我认为settings.py在你的应用程序包中创建一个很常见的东西,你可以在其中定义你的设置:

from django.conf import settings
FOO = getattr(settings, 'FOO', "default_value")
Run Code Online (Sandbox Code Playgroud)

在您的应用中,您可以从应用的settings模块中导入它们:

from myapp.settings import *

def print_foo():
    print FOO
Run Code Online (Sandbox Code Playgroud)

但我认为每个人都认为Django缺乏更好的通用架构!如果您正在寻找一种更复杂的方法来处理这个问题,那么有一些第三方应用程序就像django-appconf一样,但如果您想为您的应用程序引入另外一个依赖,那么您的决定就是它!

  • 虽然这很好,但是当我来测试使用该设置的代码时,我遇到了问题.`django.test.override_settings`似乎不能很好地使用这种方法 - 如果我覆盖测试的设置,我的代码将从`myapp.settings`导入它. (11认同)
  • 很好的答案。这也可以扩展到“models.py”中,请参阅[本教程以了解概述](http://blog.muhuk.com/2010/01/26/developing-reusable-django-apps-app-设置.html)。 (2认同)
  • 或者不用“reload”,只需使用另一个答案中提到的“AppConfig.ready”。真正的节省者。 (2认同)

Jan*_*zny 6

看来,我在那看到的每个解决方案都倾向于创建应用程序设置,代理,包装等内容的内部副本。当在运行时修改设置时(如在测试中所做的那样),这会造成混乱并产生问题。

对我来说,所有设置都属于其中django.conf.settings,仅在那里。您不应从其他地方阅读它们,也不应将其复制以备后用(因为它们可能会更改)。您应该将它们设置一次,以后不要再理会默认值了。

我了解在内部使用应用程序设置时冲掉应用程序前缀的冲动,但这也是恕我直言的一个好主意。遇到麻烦时,SOME_APP_FOO将不会产生结果,因为它在FOO内部使用。对吧?还有什么呢?还记得显式更好吗?

恕我直言,最好的方法是在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')
Run Code Online (Sandbox Code Playgroud)

或者最好在一个单独的模块中以简洁明了的方式定义它们,并将它们作为(或接近)Settings类的实现导入:

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))
Run Code Online (Sandbox Code Playgroud)

我不确定使用__dict__最好的解决方案,但是您知道了,可以始终通过用户hasattr/ setattr组合来获得效果。

这样,您的应用程序设置为:

  1. 暴露给其他人-如果在极少数情况下他们应该依赖它们,则当然可以配置应用程序以便彼此依赖
  2. 像其他设置一样正常读取
  3. 在自己的模块中很好地声明
  4. 懒惰的
  5. 控制它们的设置方式django.conf.settings-如果需要,可以实现一些名称转换

PS。有一个警告,关于不要在运行时修改设置,但不能解释原因。所以我认为这一次在初始化期间可能是一个合理的例外;)

PS2。不要命名单独的模块只是settings当你把这个可能会比较混乱settingsdjango.conf

  • 不知道为什么这没有更多的赞成票。绝对是唯一的出路。如果`app_settings.py` 不能用于单元测试,那么它就不是一个解决方案.. 这个很完美(使用`hasattr` 和`setattr`) (2认同)

小智 5

这个怎么样?

在 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)
Run Code Online (Sandbox Code Playgroud)

在 myapp/other.py 中:

import myapp.settings

print myapp.settings.FOO
Run Code Online (Sandbox Code Playgroud)

鉴于ncoghlan 的这个答案,我觉得这样使用 globals() 没问题。