Django之settings源码分析

配置文件

  • 一个是暴露给用户可以自定义的配置文件,项目根目录下的setting.py文件
  • 一个是全局的系统默认的配置,当用户不做任何配置的时候自动加载默认配置

解决疑问

  • 为什么配置文件必须是大写
  • 为什么当前用户配置了就使用用户配置的,不配置就使用默认的

源码分析

切入点from django import settings

  1. settings = LazySettings()

可以看到是类实例化对象,点击LazySetting()查看源码

  1. class LazySettings(LazyObject):
  2. def _setup(self, name=None):
  3. # os.environ 是获取环境变量中所有的配置,相当于一个全局字典,这里取出ENVIRONMENT_VARIABLE
  4. settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
  5. if not settings_module:
  6. ......
  7. self._wrapped = Settings(settings_module)

_setup是一个隐藏方法会自动触发,点击ENVIRONMENT_VARIABLE

  1. ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"

Django的入口文件是manage.py(可以看成启动文件)

  1. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

os.environ.setdefault()相当于给字典添加键值对,而上面对应的值就是Django暴露给用户的自定义配置文件路径。

返回LazySetting类当中分析

  1. class LazySettings(LazyObject):
  2. def _setup(self, name=None):
  3. # 这里相当于是 settings_module = 'mysite.settings'
  4. settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
  5. ......
  6. # 这里是将settings_module,也就是'mysite.settings'传入到Settings类中实例化得到一个对象
  7. self._wrapped = Settings(settings_module)

再点击进入Settings类中查看类代码

  1. from django.conf import global_settings
  2. class Settings(object):
  3. def __init__(self, settings_module): # 'mysite.settings'
  4. # dir()获取全局配置文件里面所有的变量名,循环取出来
  5. for setting in dir(global_settings):
  6. if setting.isupper(): # 校验是否是纯大写(这也就是配置变量小写无效)
  7. # getattr()获取全局变量中所有的大写配置的值
  8. # setattr()再将该配置名以及对应的值添加到Settings对象中
  9. setattr(self, setting, getattr(global_settings, setting))
  10. # 通过反射获取系统配置文件中所有的大写变量名和对应的值,赋值给settings对象
  11. # 将'mysite.settings'赋值给self.SETTINGS_MODULE后面使用
  12. self.SETTINGS_MODULE = settings_module
  13. # importlib模块:以字符串的方式导入模块,也就导入了暴露给用户的配置文件
  14. # from mysite import settings
  15. mod = importlib.import_module(self.SETTINGS_MODULE)
  16. for setting in dir(mod):
  17. if setting.isupper():
  18. # 循环取出暴露给用户配置文件中的所有大写的配置值
  19. setting_value = getattr(mod, setting)
  20. .......
  21. # 然后再将其设置进入Settings对象中,有就覆盖,没有就添加
  22. setattr(self, setting, setting_value)

基于setting源码编程

  1. import importlib
  2. import os
  3. from lib.conf import golobal_settings
  4. class Settings(object):
  5. def __init__(self):
  6. # 先循环获取全局配置文件中所有的名字
  7. for name in dir(golobal_settings):
  8. # 筛选出纯大写的配置
  9. if name.isupper():
  10. # 根据大写的名字获取对应的值
  11. value = getattr(golobal_settings, name)
  12. # 给对象设置键值对
  13. setattr(self, name, value)
  14. # 获取暴露给用户的自定义配置文件字符串路径
  15. module_path_str = os.environ.get('SETTINGS') # conf.settings
  16. # 根据字符串路径导入模块
  17. module_name = importlib.import_module(module_path_str)
  18. # 循环获取暴露给用户配置文件中所有的名字
  19. for name in dir(module_name):
  20. if name.isupper():
  21. value = getattr(module_name, name)
  22. setattr(self, name, value)
  23. settings = Settings()

start.py

  1. import os
  2. import sys
  3. sys.path.append(os.path.dirname(__file__))
  4. if __name__ == '__main__':
  5. # 项目全值设置一个键值对,值必须是暴露给用户的配置文件字符串路径
  6. os.environ['SETTINGS'] = 'conf.settings'
  7. from lib.conf import settings
  8. print(settings.NAME)
  9. print(settings.GENDER)