Django之settings源码分析
配置文件
- 一个是暴露给用户可以自定义的配置文件,项目根目录下的
setting.py文件 - 一个是全局的系统默认的配置,当用户不做任何配置的时候自动加载默认配置
解决疑问
- 为什么配置文件必须是大写
- 为什么当前用户配置了就使用用户配置的,不配置就使用默认的
源码分析
切入点from django import settings
settings = LazySettings()
可以看到是类实例化对象,点击LazySetting()查看源码
class LazySettings(LazyObject):def _setup(self, name=None):# os.environ 是获取环境变量中所有的配置,相当于一个全局字典,这里取出ENVIRONMENT_VARIABLEsettings_module = os.environ.get(ENVIRONMENT_VARIABLE)if not settings_module:......self._wrapped = Settings(settings_module)
_setup是一个隐藏方法会自动触发,点击ENVIRONMENT_VARIABLE。
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
Django的入口文件是manage.py(可以看成启动文件)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
os.environ.setdefault()相当于给字典添加键值对,而上面对应的值就是Django暴露给用户的自定义配置文件路径。
返回LazySetting类当中分析
class LazySettings(LazyObject):def _setup(self, name=None):# 这里相当于是 settings_module = 'mysite.settings'settings_module = os.environ.get(ENVIRONMENT_VARIABLE)......# 这里是将settings_module,也就是'mysite.settings'传入到Settings类中实例化得到一个对象self._wrapped = Settings(settings_module)
再点击进入Settings类中查看类代码
from django.conf import global_settingsclass Settings(object):def __init__(self, settings_module): # 'mysite.settings'# dir()获取全局配置文件里面所有的变量名,循环取出来for setting in dir(global_settings):if setting.isupper(): # 校验是否是纯大写(这也就是配置变量小写无效)# getattr()获取全局变量中所有的大写配置的值# setattr()再将该配置名以及对应的值添加到Settings对象中setattr(self, setting, getattr(global_settings, setting))# 通过反射获取系统配置文件中所有的大写变量名和对应的值,赋值给settings对象# 将'mysite.settings'赋值给self.SETTINGS_MODULE后面使用self.SETTINGS_MODULE = settings_module# importlib模块:以字符串的方式导入模块,也就导入了暴露给用户的配置文件# from mysite import settingsmod = importlib.import_module(self.SETTINGS_MODULE)for setting in dir(mod):if setting.isupper():# 循环取出暴露给用户配置文件中的所有大写的配置值setting_value = getattr(mod, setting).......# 然后再将其设置进入Settings对象中,有就覆盖,没有就添加setattr(self, setting, setting_value)
基于setting源码编程
import importlibimport osfrom lib.conf import golobal_settingsclass Settings(object):def __init__(self):# 先循环获取全局配置文件中所有的名字for name in dir(golobal_settings):# 筛选出纯大写的配置if name.isupper():# 根据大写的名字获取对应的值value = getattr(golobal_settings, name)# 给对象设置键值对setattr(self, name, value)# 获取暴露给用户的自定义配置文件字符串路径module_path_str = os.environ.get('SETTINGS') # conf.settings# 根据字符串路径导入模块module_name = importlib.import_module(module_path_str)# 循环获取暴露给用户配置文件中所有的名字for name in dir(module_name):if name.isupper():value = getattr(module_name, name)setattr(self, name, value)settings = Settings()
start.py
import osimport syssys.path.append(os.path.dirname(__file__))if __name__ == '__main__':# 项目全值设置一个键值对,值必须是暴露给用户的配置文件字符串路径os.environ['SETTINGS'] = 'conf.settings'from lib.conf import settingsprint(settings.NAME)print(settings.GENDER)
