Django之settings源码分析
配置文件
- 一个是暴露给用户可以自定义的配置文件,项目根目录下的
setting.py
文件 - 一个是全局的系统默认的配置,当用户不做任何配置的时候自动加载默认配置
解决疑问
- 为什么配置文件必须是大写
- 为什么当前用户配置了就使用用户配置的,不配置就使用默认的
源码分析
切入点from django import settings
settings = LazySettings()
可以看到是类实例化对象,点击LazySetting()
查看源码
class LazySettings(LazyObject):
def _setup(self, name=None):
# os.environ 是获取环境变量中所有的配置,相当于一个全局字典,这里取出ENVIRONMENT_VARIABLE
settings_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_settings
class 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 settings
mod = 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 importlib
import os
from lib.conf import golobal_settings
class 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 os
import sys
sys.path.append(os.path.dirname(__file__))
if __name__ == '__main__':
# 项目全值设置一个键值对,值必须是暴露给用户的配置文件字符串路径
os.environ['SETTINGS'] = 'conf.settings'
from lib.conf import settings
print(settings.NAME)
print(settings.GENDER)