【问题标题】:How to define a default value for a custom Django setting如何为自定义 Django 设置定义默认值
【发布时间】:2011-08-01 21:01:57
【问题描述】:

Django 文档mentions,您可以将自己的设置添加到django.conf.settings。所以如果我的项目的settings.py 定义了

APPLES = 1

我可以在该项目的应用程序中使用settings.APPLES 访问它。

但是如果我的settings.py 没有定义那个值,那么访问settings.APPLES 显然是行不通的。如果settings.py 中没有显式设置,有没有办法为APPLES 定义一个默认值?

我最好在需要设置的模块/包中定义默认值。

【问题讨论】:

    标签: django default-value django-settings


    【解决方案1】:

    在我的应用程序中,我有一个单独的 settings.py 文件。在该文件中,我有一个 get() 函数,它在项目 settings.py 文件中进行查找,如果未找到,则返回默认值。

    from django.conf import settings
    
    def get(key, default):
        return getattr(settings, key, default)
    
    
    APPLES = get('APPLES', 1)
    

    然后我需要在哪里访问我拥有的 APPLES:

    from myapp import settings as myapp_settings
    
    myapp_settings.APPLES
    

    这允许在项目 settings.py 中进行覆盖,getattr 将首先在那里检查并在找到该属性时返回该值,或者使用您的应用程序设置文件中定义的默认值。

    【讨论】:

    • 这不是很脆弱吗?不依赖在app_settings.py 之前导入的项目settings.py
    • @Flimm 是的。如果你尝试直接导入myapp_settings,它会在第一个getattr处初始化Django的LazySettings,并给出配置错误(因为this line将返回部分评估的myapp_settings模块而我们评估它,而不是进入一个无限的导入循环)。我还没有找到一个干净的解决方法。
    【解决方案2】:

    怎么样:

    getattr(app_settings, 'SOME_SETTING', 'default value')
    

    【讨论】:

    • 这比这里的其他一些建议要简单得多,但是如果您打算多次使用设置/变量,那么您就打破了 DRY 概念,在这种情况下,其他解决方案可能会起作用。值得深思:)
    • 它是如何破坏 DRY 的?
    • 如果您打算在应用程序中多次使用 SOME_SETTING,那么您必须将 getattr(app_settings, 'SOME_SETTING', default_value) 放置在您使用它的任何地方
    • 随心所欲地设置默认值。
    • app_settings 来自哪里?那应该是django.conf.settings吗?
    【解决方案3】:

    这里有两个解决方案。对于这两者,您可以在应用程序中设置 settings.py 文件并使用默认值填充它们。

    为单个应用配置默认值

    在您的代码中使用from MYAPP import settings 而不是from django.conf import settings

    编辑YOURAPP/__init__.py:

    from django.conf import settings as user_settings
    from . import settings as default_settings
    
    class AppSettings:
        def __getattr__(self, name):
            # If the setting you want is filled by the user, let's use it.
            if hasattr(user_settings, name):
                return getattr(user_settings, name)
    
            # If the setting you want has a default value, let's use it.
            if hasattr(default_settings, name):
                return getattr(default_settings, name)
    
            raise AttributeError("'Settings' object has no attribute '%s'" % name)
    
    settings = AppSettings()
    

    为整个项目配置默认值

    在您的代码中使用from MYPROJECT import settings 而不是from django.conf import settings

    编辑MYPROJECT/MYPROJECT/__init__.py

    import os, sys, importlib
    from . import settings as user_settings
    
    def get_local_apps():
        """Returns the locally installed apps names"""
        apps = []
        for app in user_settings.INSTALLED_APPS:
            path = os.path.join(user_settings.BASE_DIR, app)
            if os.path.exists(path) and app != __name__:
                apps.append(sys.modules[app])
        return apps
    
    class AppSettings:
        SETTINGS_MODULE = 'settings'
    
        def __getattr__(self, setting_name):
    
            # If the setting you want is filled by the user, let's use it.
            if hasattr(user_settings, setting_name):
                return getattr(user_settings, setting_name)
    
            # Let's check every local app loaded by django.
            for app in get_local_apps():
                module_source = os.path.join(app.__path__[0], "%s.py" % self.SETTINGS_MODULE)
                module_binary = os.path.join(app.__path__[0], "%s.pyc" % self.SETTINGS_MODULE)
                if os.path.exists(module_source) or os.path.exists(module_binary):
                    module = importlib.import_module("%s.%s" % (app.__name__, self.SETTINGS_MODULE))
    
                    # Let's take the first default value for this setting we can find in any app
                    if hasattr(module, setting_name):
                        return getattr(module, setting_name)
    
            raise AttributeError("'Settings' object has no attribute '%s'" % setting_name)
    
    settings = AppSettings()
    

    这个解决方案可能看起来更容易安装,但它并不能保证会返回好的默认值。如果多个应用程序在它们的 settings.py 中声明了相同的变量,您无法确定哪一个会返回您要求的默认值。

    【讨论】:

      【解决方案4】:

      从 Mike 的回答开始,我现在将默认设置处理封装到一个界面易于使用的类中。

      辅助模块:

      from django.conf import settings
      
      class SettingsView(object):
         class Defaults(object):
            pass
      
         def __init__(self):
            self.defaults = SettingsView.Defaults()
      
         def __getattr__(self, name):
            return getattr(settings, name, getattr(self.defaults, name))
      

      用法:

      from localconf import SettingsView
      
      settings = SettingsView()
      settings.defaults.APPLES = 1
      
      print settings.APPLES
      

      这将打印来自django.conf.settings 的值,如果未在此处设置,则为默认值。这个settings 对象也可用于访问所有标准设置值。

      【讨论】:

      • 我认为应用程序特定的设置应该明确命名并且与主要设置不同,以便于阅读。
      【解决方案5】:

      我最近遇到了同样的问题,并创建了一个 Django 应用程序,专门用于这种情况。它允许您为某些设置定义默认值。然后它首先检查是否在全局设置文件中设置了设置。如果没有,则返回默认值。

      我已经对其进行了扩展,还允许对默认值进行一些类型检查或预处理(例如,可以在加载时将点分类路径转换为类本身)

      可以在以下位置找到该应用程序:https://pypi.python.org/pypi?name=django-pluggableappsettings&version=0.2.0&:action=display

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-28
        • 1970-01-01
        • 2012-02-23
        • 2013-09-26
        • 2014-06-09
        • 2021-08-22
        相关资源
        最近更新 更多