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 ...
随机推荐
- Vue---mock.js 使用
mockjs 概述 在我们的生产实际中,后端的接口往往是较晚才会出来,并且还要写接口文档,于是我们的前端的许多开发都要等到接口给我们才能进行,这样对于我们前端来说显得十分的被动,于是有没有可以制造假数 ...
- SpringBoot 整合 Elasticsearch深度分页查询
es 查询共有4种查询类型 QUERY_AND_FETCH: 主节点将查询请求分发到所有的分片中,各个分片按照自己的查询规则即词频文档频率进行打分排序,然后将结果返回给主节点,主节点对所有数据进行汇总 ...
- 一个自动管理项目的Makefile(C语言)
Linux 是所有嵌入式软件工程师绕不过去的坎, makefile 是在Linux系统中绕不过去的坎. 花了几天时间初步学习和了解了makefile 的作用以及功能,并且制作了一个通用型的makefi ...
- 单点登录 - API 认证系统 Passport(二)
安装 composer require laravel/passport=~4.0 notes: 1)确保系统安装unzip.zip等命令. 2)composer 安装出现 Authenticatio ...
- 机器学习之scikit-learn库
前面讲到了,这个库适合学习,轻量级,所以先学它. 安装就不讲了,简单.不过得先安装numpy和pandas库才能安装scikit-learn库. 如果安装了anaconda得话,会自带有这个库. -- ...
- VueI18n - 多语言国际化支持插件
VueI18n介绍 vue-i18n是一个vue组件,主要功能是提供国际化多语言的支持.例如项目中打印收费单功能,需要支持中英文打印,使用该组件就很容易的实现,而不必写两份打印单页面. 使用方法 安装 ...
- python协程总结
概述 python多线程中因为有GIL(Global Interpreter Lock 全局解释器锁 )的存在,所以对CPU密集型程序显得很鸡肋:但对IO密集型的程序,GIL会在调用IO操作前释放,所 ...
- 如何提高web应用的吞吐量
这篇博文所列举的优化手段是针对比较传统项目,但是想提高系统的吞吐量现在时髦的技术还是那些前后端未分离, 使用nginx当成静态资源服务器去代理我们的静态资源 是谁限制了Throughput? 当我们对 ...
- SpringBoot之微服务日志链路追踪
SpringBoot之微服务日志链路追踪 简介 在微服务里,业务出现问题或者程序出的任何问题,都少不了查看日志,一般我们使用 ELK 相关的日志收集工具,服务多的情况下,业务问题也是有些难以排查,只能 ...
- layer弹框的上面各个属性 -可配置
<script type="text/javascript"> 12 //eg 13 layer.open({ 14 title:"标题信息提示", ...