Django中的module的加载是通过反射来完成的,借助importlib中的import_module函数来实现的动态加载。import_module的内部通过使用了递归和线程锁,字符串的切割,实现模块的加载。

主要有以下几个步骤:

根据字符串的形式导入模块

假设在有以下的类跟方法:


path = "handler.basic.BaseHandler"


func_name = "process_request"

导入目标函数:

import importlib

# 通过切割拿到模块和类名
module_path,cls_name = path.rsplit('.', 1)
# 导入模块
module = importlib.import_module(module_path)
print(module)

去模块中找到相应的类

通过反射拿到类。

cls =  getattr(module, cls)

根据相应的类实例化

实例化对象:

obj = cls()

执行对象方法

通过反射拿到方法,

func = getattr(obj, func_name)
fuc()

Django中间件源码

    def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWARE (or the deprecated
MIDDLEWARE_CLASSES). Must be called after the environment is fixed (see __call__ in subclasses).
"""
self._request_middleware = []
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = [] if settings.MIDDLEWARE is None:
warnings.warn(
"Old-style middleware using settings.MIDDLEWARE_CLASSES is "
"deprecated. Update your middleware and use settings.MIDDLEWARE "
"instead.", RemovedInDjango20Warning
)
handler = convert_exception_to_response(self._legacy_get_response)
for middleware_path in settings.MIDDLEWARE_CLASSES:
mw_class = import_string(middleware_path)
try:
mw_instance = mw_class()
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
else:
logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue if hasattr(mw_instance, 'process_request'):
self._request_middleware.append(mw_instance.process_request)
if hasattr(mw_instance, 'process_view'):
self._view_middleware.append(mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.insert(0, mw_instance.process_template_response)
if hasattr(mw_instance, 'process_response'):
self._response_middleware.insert(0, mw_instance.process_response)
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.insert(0, mw_instance.process_exception)
else:
handler = convert_exception_to_response(self._get_response)
for middleware_path in reversed(settings.MIDDLEWARE):
# 从setting中的中间件的配置,切割拿到导入的模块和类名,通过反射拿到对应的类
middleware = import_string(middleware_path)
try:
# 中间件实例化对象,
mw_instance = middleware(handler)
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
else:
logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue if mw_instance is None:
raise ImproperlyConfigured(
'Middleware factory %s returned None.' % middleware_path
) if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(0, mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.append(mw_instance.process_template_response)
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.append(mw_instance.process_exception) handler = convert_exception_to_response(mw_instance) # We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._middleware_chain = handler ############################################################################## def import_string(dotted_path):
"""
Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import failed.
"""
try:
# module_path: django.middleware.csrf
# class_name: CsrfViewMiddleware
module_path, class_name = dotted_path.rsplit('.', 1)
except ValueError:
msg = "%s doesn't look like a module path" % dotted_path
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) # module_path: django.middleware.csrf
# 通过module_path导入模块
module = import_module(module_path) try:
# 拿到当前类的类名
return getattr(module, class_name)
except AttributeError:
msg = 'Module "%s" does not define a "%s" attribute/class' % (
module_path, class_name)
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) ##################################################################### def import_module(name, package=None):
"""Import a module. The 'package' argument is required when performing a relative import. It
specifies the package to use as the anchor point from which to resolve the
relative import to an absolute import. """
level = 0
if name.startswith('.'):
if not package:
msg = ("the 'package' argument is required to perform a relative "
"import for {!r}")
raise TypeError(msg.format(name))
for character in name:
if character != '.':
break
level += 1
# _gcd_import中使用了递归和线程锁,字符串的切割,实现模块的加载。
return _bootstrap._gcd_import(name[level:], package, level)

Django中模块的加载原理的更多相关文章

  1. django中的懒加载机制

    懒加载在前端中的意义: 懒加载的主要目的就是作为服务器前端的优化,减少请求次数或者延迟请求数. 实现原理: 先加载一部分数据,当触发某个条件时利用异步加载剩余的数据,新得到的数据不会影响原有数据的显示 ...

  2. 深入理解 Laravel 中 config 配置加载原理

    Laravel的配置加载其实就是加载config目录下所有文件配置.如何过使用php artisan config:cache则会把加载的配置合并到一个配置文件中,下次请求就不会再去加载config目 ...

  3. Django中的图片加载不出来解决方式记录

    背景:Python3.6 + Django2.2 在模板中的html文件中引用图片时,在浏览器中图片总是显示不出来,上网查了很多解决方式,但是都没有解决问题,最终尝试了多次后得以解决,但不清楚原理: ...

  4. Grunt-cli的执行过程以及Grunt加载原理

    通过本篇你可以了解到: 1 grunt-cli的执行原理 2 nodeJS中模块的加载过程 Grunt-cli原理 grunt-cli其实也是Node模块,它可以帮助我们在控制台中直接运行grunt命 ...

  5. node 中第三方模块的加载过程原理

    node 中第三方模块的加载过程原理 凡是第三方模块都必须通过 npm 来下载 使用的时候就可以通过require('包名') 的方式来进行加载才可以使用 不可能有任何一个第三方包和核心模块的名字是一 ...

  6. AMD-require.js模块加载原理

    项目中使用大了require.js,功能实现,现重新学习下模块加载原理相关知识,借鉴如下博文:https://blog.csdn.net/ai52011/article/details/7711361 ...

  7. Node.js require 模块加载原理 All In One

    Node.js require 模块加载原理 All In One require 加载模块,搜索路径 "use strict"; /** * * @author xgqfrms ...

  8. JS模块加载器加载原理是怎么样的?

    路人一: 原理一:id即路径 原则.通常我们的入口是这样的: require( [ 'a', 'b' ], callback ) .这里的 'a'.'b' 都是 ModuleId.通过 id 和路径的 ...

  9. js中的预加载与懒加载(延迟加载)

    js中加载分两种:预加载与延迟加载 一.  预加载,增强用户的体验,但会加载服务器的负担.一般会使用多种 CSS(background).JS(Image).HTML(<img />) . ...

随机推荐

  1. 一款 App 开发到上架

    随着互联网时代的发展,越来越多的 App 诞生啦.App 是手机软件的简称,手机主流的有 iOS.Andriod. 开发一个 App 需要哪些步骤呢?下面我和大家分享一下. 一.APP 的 idea( ...

  2. [NoiPlus2016]天天爱跑步

    巨坑 树剖学的好啊!---sfailsth 把一段路径拆成两段,向上和S->LCA,向下LCA->T 用维护重链什么的操作搞一下. sfailsth学长真不容易啊...考场上rush了4. ...

  3. LINUX 中 VSFTPD安裝

    VSFTPD 简写:vsftpd是very secure FTP daemon 的缩写,是一个完全免费的,开源代码的ftp服务器软件 特点:vsftpd是一款在LINUX发行版中最受推崇的FTP服务器 ...

  4. mknod指令详解

    mknod - make block or character special filesmknod [OPTION]... NAME TYPE [MAJOR MINOR]    option 有用的 ...

  5. IIS部署ASP.NET网站后提示只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态...

    今天,在IIS上部署网站后,出现了下面错误: 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态.还请确保在应用程序配置的 <sy ...

  6. 【codeforces 807D】Dynamic Problem Scoring

    [题目链接]:http://codeforces.com/contest/807/problem/D [题意] 给出n个人的比赛信息; 5道题 每道题,或是没被解决->用-1表示; 或者给出解题 ...

  7. 你必须搞清楚的String,StringBuilder,StringBuffer

    String,StringBuilder 以及 StringBuffer 这三个类的关系与区别一直是 Java 的经典问题,这次就来讲一下关于这三个类的一些知识 一. 简单对比 String : 字符 ...

  8. POJ 2470 Ambiguous permutations(简单题 理解题意)

    [题目简述]:事实上就是依据题目描写叙述:A permutation of the integers 1 to n is an ordering of these integers. So the n ...

  9. 使用 python 读写中文json

    读写中文json )   输出中文的json. 通过使用 ensure_ascii=False,输出原有的语言文字.indent參数是缩进数量. 更改写文件格式 将上一步导出的 string 直接写文 ...

  10. POJ1390 Blocks 【动态规划】

    Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4173   Accepted: 1661 Descriptio ...