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 ...
随机推荐
- Unity5-ABSystem(四):AssetBundle依赖
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/lodypig/article/detai ...
- Docker之构建上下文详解
昨天写了使用 Dockerfile 定制镜像.其中构建上下文这一块没有写,今天把这一块单独拿出来写一下. Docker镜像构建 简单说下构建镜像步骤: cd Dockerfile 所在目录; 执行 d ...
- python自带的IDLE编译器,听说大神都用这个(附python下载安装教程)
python这两年这么火,学的人越来越多,小伙伴们都用什么编译器了? 今天教大家安装python并熟悉python自带的编译器IDLE. 第一步,进入python官网https://www.pytho ...
- textarea如何实现高度自适应(一)
转自轩枫阁 - http://www.xuanfengge.com/textarea-on-how-to-achieve-a-high-degree-of-adaptive.html 方法一:div模 ...
- php经典设计模式和Trait类代码的复用
PHP经典设计模式 <?php /** * 单例模式 */ class Site { #定义属性 public $siteName; #定义本类的静态实例 protected static $i ...
- 医生智能提醒小程序数据库设计心得——Legends Never Die
数据库设计心得 根据我们小组数据库设计的整个流程,我们将整个数据库设计划分为两个具体的阶段,在每个阶段需要进行不同的准备,有不同的注意事项,接下来我们将结合在数据库设计过程中遇到的一些问题和困难,提出 ...
- [考试反思]1013csp-s模拟测试72:距离
最近总是这个样子. 看上去排名好像还可以,但是实际上离上面的分差往往能到80分,但是身后的分差其实只有10/20分. 比上不足,比下也不怎么的. 所以虽然看起来没有出rank10,但是在总分排行榜上却 ...
- .NET Core 3.0 单元测试与 Asp.Net Core 3.0 集成测试
单元测试与集成测试 测试必要性说明 相信大家在看到单元测试与集成测试这个标题时,会有很多感慨,我们无数次的在实践中提到要做单元测试.集成测试,但是大多数项目都没有做或者仅建了项目文件.这里有客观原因, ...
- [笔记] HOW2J.CN网站记录的java笔记_第四部分_HTML
1.写一个显示Hello World的网页, <html> <body> <p>Hello World</p> </body> </h ...
- flume安装和介绍
一.安装1.flume-ng-1.5.0-cdh5.3.6.tar.gz 下载链接:https://pan.baidu.com/s/1AWPGP2qnY6_VpYr_iSnJ3w 密码:tiog2.对 ...