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延时加载的对象中. 配置文件大写的原因也只是因为源码只处理全大写的属性而已.
参考
Django的settings文件部分源码分析的更多相关文章
- DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
- python-flask-配置文件的源码分析
方式一:app.config['xx'] = 'xxx'源码分析:#第1步:class Flask(_PackageBoundObject): self.config = self.make_c ...
- Django——基于类的视图源码分析 二
源码分析 抽象类和常用视图(base.py) 这个文件包含视图的顶级抽象类(View),基于模板的工具类(TemplateResponseMixin),模板视图(TemplateView)和重定向视图 ...
- Django REST framework —— 认证组件源码分析
我在前面的博客里已经讲过了,我们一般编写API的时候用的方式 class CoursesView(ViewSetMixin,APIView): pass 这种方式的有点是,灵活性比较大,可以根据自己的 ...
- Django(60)Django内置User模型源码分析及自定义User
前言 Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了.它的完整的路径是在django.contrib.auth.models.User. User模型源码分析 ...
- django的RestFramework模块的源码分析
一.APIView源码分析 查看源码的前提要知道,找函数方法必须先在自己的类中找,没有再往父类找,一层一层网上找,不能直接按ctrl点击 在我们自己定义的类中没有as_view方法的函数,所以肯定是继 ...
- Django rest framework框架——APIview源码分析
一.什么是rest REST其实是一种组织Web服务的架构,而并不是我们想象的那样是实现Web服务的一种新的技术,更没有要求一定要使用HTTP.其目标是为了创建具有良好扩展性的分布式系统. 可用一句话 ...
- Django(55)GenericAPIView源码分析
源码分析 GenericAPIView继承自APIView,也就是在APIView基础上再做了一层封装,源码如下: class GenericAPIView(views.APIView): query ...
- Django REST framework —— 权限组件源码分析
在上一篇文章中我们已经分析了认证组件源码,我们再来看看权限组件的源码,权限组件相对容易,因为只需要返回True 和False即可 代码 class ShoppingCarView(ViewSetMix ...
随机推荐
- Java 用单向循环链表实现 约瑟夫问题
public class lianbiao2 { class Node{ Node next; int number; public Node getNext() { return next; } p ...
- 获得shell的几种姿势
windows提权 1.通过sqlmap连接mysql获取shell (1)直接连接数据库 sqlmap.py -d "mysql://root:123456@127.0.0.1:3306/ ...
- pymssql的Connection相关特性浅析
关于Python的pymssql模块,之前研究时总结了"pymssql默认关闭自动模式开启事务行为浅析"这篇博客,但是在测试过程中又发现了几个问题,下面对这些问题做一些浅析,如有不 ...
- emacs考场短配置
(set-background-color "gray15") (set-foreground-color "gray") ;;设置颜色 (global-set ...
- ORACLE存储过程的创建和执行的简单示例和一些注意点
此示例的主要目的主要是为了了解在PL/SQL环境下怎么创建和执行存储过程. 存储过程所涉及的DataTable: 第一步:创建游标变量 游标是ORACLE系统在内存中开辟的一个工作区,主要用来存储SE ...
- 易初大数据 2019年10月20日 spss习题 王庆超
一.选择题 1.有关spss数据字典的说法,正确的是:D A.SPSS数据集的数据字典可以复制到其他数据集中 B.SPSS数据集的数据字典是不能复制的 C.SPSS的数据字典可以通过“复制”和“黏贴” ...
- jquery 路径动画贝塞尔动画
jquery 路径动画贝塞尔动画 <pre><!DOCTYPE html><!DOCTYPE html><html> <head> < ...
- day5-字典专区
# 字典# dict 1.fromkeys()根据序列,创建字典,并指定统一的值 v = dict.fromkeys(["],123) print(v) {': 123} 2.get()根据 ...
- 使用vue-cli搭建项目开发环境
一.前言 本篇文章主要是使用vue-cli搭建一个简单的vue项目,这个项目在其他文章中作为代码演示的环境会一直使用. 注意:默认大家的电脑已经安装nodejs,所以这里不总结nodejs的安装. 二 ...
- google在nature上发表的关于量子计算机的论文(Quantum supremacy using a programmable superconducting processor 译)— 附论文
Google 2019年10月23号发表在Nature(<自然><科学>及<细胞>杂志都是国际顶级期刊,貌似在上面发文两篇,就可以评院士了)上,关于量子计算(基于 ...