Django 源码阅读(3): settings配置加载

  • 继续看execute() 函数,分析下 settings.INSTALLED_APPS 作用机制,看看作为可能在整个 web 程序起配置作用的配置模块是如何构建的.
    try:
        options, args = parser.parse_known_args(self.argv[2:])
        handle_default_options(options)
    except CommandError:
        pass  # Ignore any option errors at this point.

    try:
        settings.INSTALLED_APPS

settings的懒加载

  • django 的配置采用了延时加载(就是在需要用到的时候再加载),一般手段有代理类,线程,计时器。django 中使用 LazyObject 代理类。加载函数是 _setup 函数,当获取属性时才会去加载。
settings = LazySettings()

class LazySettings(LazyObject):
    """
    A lazy proxy for either global Django settings or a custom settings object.
    The user can manually configure settings prior to using them. Otherwise,
    Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
    """
    def _setup(self, name=None):
        ...
        self._wrapped = Settings(settings_module)
	...
    def __getattr__(self, name):
        """Return the value of a setting and cache it in self.__dict__."""
        if self._wrapped is empty:
            self._setup(name)
        val = getattr(self._wrapped, name)
        self.__dict__[name] = val
        return val

    def __setattr__(self, name, value):
        """
        Set the value of setting. Clear all cached values if _wrapped changes
        (@override_settings does this) or clear single values when set.
        """
        if name == '_wrapped':
            self.__dict__.clear()
        else:
            self.__dict__.pop(name, None)
        super().__setattr__(name, value)
  • LazySettings 继承自 LazyObject 类,它重写了 getattrsetattr 方法,那么在调用 settings.INSTALLED_APPS 时,会通过其自定义的 getattr 方法实现,从中可以看出,所有属性都是从 self._wrapped 也就是 Settings(settings_module) 这个实例中取得的。

配置文件的加载

    def _setup(self, name=None):
        """
        Load the settings module pointed to by the environment variable. This
        is used the first time settings are needed, if the user hasn't
        configured settings manually.
        """
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        if not settings_module:
            desc = ("setting %s" % name) if name else "settings"
            raise ImproperlyConfigured(
                "Requested %s, but settings are not configured. "
                "You must either define the environment variable %s "
                "or call settings.configure() before accessing settings."
                % (desc, ENVIRONMENT_VARIABLE))

        self._wrapped = Settings(settings_module)
  • ENVIRONMENT_VARIABLE 的值其实就是 manage.py 中的 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') 中的mysite.settings,通过 getter/setter 方法,对 Settings 对象的操作变为对私有成员 self._wrapped 对象的调用上(因为第一次使用settings对象时,已经将私有成员 self._wrapped 初始化为 Settings 类实例)。
class Settings:
    def __init__(self, settings_module):
        # update this dict from global settings (but only for ALL_CAPS settings)
        # 设置默认配置
        for setting in dir(global_settings):
            if setting.isupper():
                setattr(self, setting, getattr(global_settings, setting))

        # store the settings module in case someone later cares
        self.SETTINGS_MODULE = settings_module
		# 加载配置文件 settings.py
        mod = importlib.import_module(self.SETTINGS_MODULE)

        tuple_settings = (
            "INSTALLED_APPS",
            "TEMPLATE_DIRS",
            "LOCALE_PATHS",
        )
        self._explicit_settings = set()
        for setting in dir(mod):
            if setting.isupper():
                setting_value = getattr(mod, setting)

                if (setting in tuple_settings and
                        not isinstance(setting_value, (list, tuple))):
                    raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
                setattr(self, setting, setting_value)
                self._explicit_settings.add(setting)

        ...
  • 接下来可以看看Settings 类具体都干了啥?构造函数会先通过 global_settings 来设置其属性,使用 importlib.import_module 来加载用户自定义(读取 mysite.settings)的配置模块,完成全局实例的初始化,实例化后,配置懒加载也就完成了, 程序就回到 execute 函数,接下去就是运行 django.setup() 函数了。
  • 设置的特定的属性;主要有INSTALLED_APPS、TEMPLATE_DIRS、LOCALE_PATHS 这几个key,默认都是空元组,这几个key的解释如下:
    • INSTALLED_APPS,它表示项目中哪些 app 处于激活状态。元组中的字符串,除了django默认自带的命令之外,就是我们自己定义的app,也就是用python manage.py所启动的app了。
    • TEMPLATE_DIRS,它表示模板文件的所处路径。
    • LOCALE_PATHS,它表示Django将在这些路径中查找包含实际翻译文件的 <locale_code>/LC_MESSAGES 目录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值