zoukankan      html  css  js  c++  java
  • Django的settings文件部分源码分析

    Django的settings文件部分源码分析

    在编写Django项目的过程中, 其中一个非常强大的功能就是我们可以在settings文件配置许多选项来完成我们预期的功能, 并且这些配置还必须大写, 否则就不会生效. 此外, Django自身还有一套更详细的配置, 那Django是如何做到用户配置了相关配置就使用用户的配置, 否则就使用自己默认的配置. 带着这样的疑问, 去查看了用户配置项相关的源码部分.

    过程分析

    首先启动Django项目, 一般Django都是通过python manage.py runserver这句命令启动的. 从这个入口函数出发, 主要执行了下面3句话.

    if __name__ == "__main__":
        # settings文件配置到环境变量
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "auth_learn.settings")
        from django.core.management import execute_from_command_line
        # 解析并执行命令行参数
        execute_from_command_line(sys.argv)
    

    上面会将我们用户的配置文件(项目下的settings文件)设置到当前环境变量里面.

    顺着代码的流程下去.

    def execute_from_command_line(argv=None):
        """
        运行了一个命令管理工具, 将命令行的参数传到这个对象中, 并执行
        """
        utility = ManagementUtility(argv)
        utility.execute()
    

    继续往下运行

    def execute(self):
        # 解析命令行参数列表的第一个参数
        subcommand = self.argv[1]
        parser = CommandParser(None, usage="%(prog)s subcommand [options] [args]", add_help=False)
        options, args = parser.parse_known_args(self.argv[2:])
        handle_default_options(options)
        ...
    
        try:
            # 这句话就是重点了, 开始加载app
            settings.INSTALLED_APPS
        except ImproperlyConfigured as exc:
            self.settings_exception = exc
    
        ...
    

    看到这, 终于看到了和settings文件相关的代码了. 跟进去.

    settings = LazySettings()
    

    看到了settings是一个懒加载(延时加载)的LazySettings类的实例对象.

    继续跟进LazySettings的定义

    class LazySettings(LazyObject):
        def _setup(self, name=None):
            settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
            self._wrapped = Settings(settings_module)
       def __getattr__(self, name):
            if self._wrapped is empty:
                self._setup(name)
            val = getattr(self._wrapped, name)
            self.__dict__[name] = val  # 用到了直接缓存到__dict__里面
            return val
        ...
    

    发现LazySettings类继承自LazyObject, 本身并没有__init__方法, 所以继续往父类跟进

     _wrapped = None
     def __init__(self):
        self._wrapped = empty
    

    父类什么也没有定义, 就是一个空对象. 所以settings对象初始化后什么属性也没有, 这时候Django调用settings.INSTALLED_APPS这句话就是懒加载的核心. 所谓懒加载,就是在需要用到的时候再加载. 一般手段有代理类,线程... Django中使用 LazyObject 代理类。加载函数是 _setup 函数,当获取属性时才会去加载。

    LazySettings 继承自 LazyObject 类,它重写了 __getattr____setattr__ 方法,那么在调用 settings.INSTALLED_APPS 时,就会触发 __getattr__ 这个双下方法. 我们知道, 初始化的时候, settings对象就是一个empty空对象.这就会去调用加载函数_setup函数

    ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
    def _setup(self, name=None):
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        self._wrapped = Settings(settings_module)
    

    第一句话, setting_module就是从环境变量中获取我们用户自定义的配置文件, 这在刚启动manage.py文件就已经定义好了. 接下来就去实例化一个Settings对象. 从这就可以得出结论通过settings对象的属性都是从_wrapped这个私有属性获取来的, 或者说是从Settings实例对象中获取来的.

    继续跟进Settings类的源码.

    # global_settings就是一个django内部的全局配置文件
    from django.conf import global_settings
    class Settings(object):
        def __init__(self, settings_module):
            # 这句话就是遍历全局配置, 将所有的属性添加到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
    	   # 这里就是动态的将我们用户的自定义配置文件模块导入 
            mod = importlib.import_module(self.SETTINGS_MODULE)
            self._explicit_settings = set()
            # 遍历用户自定义配置文件
            for setting in dir(mod):
                # 如果我们配置的属性不是大写, 就会无效
                if setting.isupper():
                    # 获取用户的配置属性
                    setting_value = getattr(mod, setting)
                    # 将我们配置的属性添加到settings配置文件中, 或者覆盖掉
                    # Django默认的配置属性.
                    setattr(self, setting, setting_value)
                    self._explicit_settings.add(setting)
    
    

    到了这, 开头的问题也就解决了. 来一句话总结, 就是Django先加载自己的配置文件, 然后再加载用户的配置文件覆盖掉默认的属性, 保存到一个settings延时加载的对象中. 配置文件大写的原因也只是因为源码只处理全大写的属性而已.

    参考

    1. http://www.hongweipeng.com/index.php/archives/1370/

    2. https://blog.csdn.net/qq_24551305/article/details/96486835

  • 相关阅读:
    js多个基本类型计算
    移动端弹窗滚动穿透问题
    length-of-longest-substring 无重复字符的最长子串 javascript解答
    addTwoNumbers两数之和 javascript解答
    two-sum两数之和 javascript解答
    js防抖和节流
    React / Vue 项目时为什么要在列表组件中写 Key,其作用是什么?
    二进制文件流处理笔记
    ES6 class 类的理解(一)
    django之js模板插件artTemplate的使用
  • 原文地址:https://www.cnblogs.com/yscl/p/11614807.html
Copyright © 2011-2022 走看看