Django源码解读之读取settings配置文件(一)

Django采用懒加载的方式将配置文件的加载到全局变量对象settings = LazySettings()的属性中

举例说明

    1. 程序入口

      os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') # 将配置文件模块的相对路径加载到环境变量中

#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') # 将配置文件模块的相对路径加载到环境变量中
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()
    1. 跳转到下面,重点看ManagementUtility 的execute方法的 settings.INSTALLED_APPS

首先settings=LzaySettings()对象,访问属性INSTALLED_APPS时,会经过 getattr(self, name)方法,

一. 第一次启动时self._wrapped is empty(empty是LazyObject的类属性)

  1. self._wrapped = Settings(settings_module)

  2. Settings中先将django.conf.global_settings.py中默认大写全局变量配置到settings的属性中.

  3. mod = importlib.import_module(self.SETTINGS_MODULE) #导入os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')模块,dir才能解析模块
    
  4. for setting in dir(mod):   #用dir来获取所有变量
                if setting.isupper():
                    value = getattr(mod, setting)
                    if (setting in tuple_settings and not isinstance(value, (list, tuple))):
                        raise ImproperlyConfigured("The %s seting must be a list or tuple" % setting)
                    setattr(self, setting, value)  # 设置self的属性
    

二. 后面再访问属性时直接从self._wrapped.dict(settings.wrapped.dict)中获取

以下是涉及到的简化源码

def execute_from_command_line(argv=None):
    """Run a ManagementUtility."""
    utility = ManagementUtility(argv)
    utility.execute()
    
 def execute(self):
        ...
        try:
            settings.INSTALLED_APPS
            print("se:",settings.INSTALLED_APPS)
        except ImproperlyConfigured as exc:
            self.settings_exception = exc
        except ImportError as exc:
            self.settings_exception = exc

settings = LazySettings() # 全局对象

class LazySettings(LazyObject):
    def _setup(self, name=None):
        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)

    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
    
class Settings:
    def __init__(self, settings_module):
        for setting in dir(global_settings):
            if setting.isupper():
                setattr(self, setting, getattr(global_settings, setting)) # 默认的全局变量(大写)
        # store settings
        self.SETTINGS_MODULE = settings_module
        mod = importlib.import_module(self.SETTINGS_MODULE) # 导入os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')模块,dir才能解析模块
        tuple_settings = (
            "INSTALLED_APPS",
            "TEMPLATE_DIRS",
            "LOCALE_PATHS",
        )
        self._explicit_settings = set()
        for setting in dir(mod):    #用dir来获取所有变量
            if setting.isupper():
                value = getattr(mod, setting)
                if (setting in tuple_settings and not isinstance(value, (list, tuple))):
                    raise ImproperlyConfigured("The %s seting must be a list or tuple" % setting)
                setattr(self, setting, value)   # 设置self的属性
 
empty = object()
class LazyObject:
    # Avoid infinite recursion when tracing __init__ (#19456).
    _wrapped = None

    def __init__(self):
        # Note: if a subclass overrides __init__(), it will likely need to
        # override __copy__() and __deepcopy__() as well.
        self._wrapped = empty

    __getattr__ = new_method_proxy(getattr)

    def __setattr__(self, name, value):
        if name == "_wrapped":
            # Assign to __dict__ to avoid infinite __setattr__ loops.
            self.__dict__["_wrapped"] = value
        else:
            if self._wrapped is empty:
                self._setup()
            setattr(self._wrapped, name, value)

    def _setup(self):
        """
        Must be implemented by subclasses to initialize the wrapped object.
        """
        raise NotImplementedError('subclasses of LazyObject must provide a _setup() method')


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容