Django应用程序入口WSGIHandler源码解析


Posted in Python onAugust 05, 2019

前言

WSGI 有三个部分, 分别为服务器(server), 应用程序(application) 和中间件(middleware). 已经知道, 服务器方面会调用应用程序来处理请求, 在应用程序中有真正的处理逻辑, 在这里面几乎可以做任何事情, 其中的中间件就会在里面展开.

Django 中的应用程序

任何的 WSGI 应用程序, 都必须是一个 start_response(status, response_headers, exc_info=None) 形式的函数或者定义了 __call__ 的类. 而 django.core.handlers 就用后一种方式实现了应用程序: WSGIHandler. 在这之前, Django 是如何指定自己的 application 的, 在一个具体的 Django 项目中, 它的方式如下:

在 mysite.settings.py 中能找到如下设置:

# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'tomato.wsgi.application'

如你所见, WSGI_APPLICATION 就指定了应用程序. 而按图索骥下去, 找到项目中的 wsgi.py, 已经除去了所有的注释:

import os 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tomato.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

因此, WSGI_APPLICATION 所指定的即为 wsgi.py 中的全局变量 application. 故伎重演, 继续找下去. 在 django.core 模块中的 wsgi.py 中找到 get_wsgi_application() 函数的实现:

from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
  """
  The public interface to Django's WSGI support. Should return a WSGI
  callable. 
  Allows us to avoid making django.core.handlers.WSGIHandler public API, in
  case the internal WSGI implementation changes or moves in the future.
 
  """
  """
  # 继承, 但只实现了 __call__ 方法, 方便使用
  class WSGIHandler(base.BaseHandler):
  """
  return WSGIHandler()

在 get_wsgi_application() 中实例化了 WSGIHandler, 并无其他操作.

WSGIHandler

紧接着在 django.core.handler 的 base.py 中找到 WSGIHandler 的实现.

# 继承, 但只实现了 __call__ 方法, 方便使用
class WSGIHandler(base.BaseHandler):
  initLock = Lock() 
  # 关于此, 日后展开, 可以将其视为一个代表 http 请求的类
  request_class = WSGIRequest 
  # WSGIHandler 也可以作为函数来调用
  def __call__(self, environ, start_response):
    # Set up middleware if needed. We couldn't do this earlier, because
    # settings weren't available. 
    # 这里的检测: 因为 self._request_middleware 是最后才设定的, 所以如果为空,
    # 很可能是因为 self.load_middleware() 没有调用成功.
    if self._request_middleware is None:
      with self.initLock:
        try:
          # Check that middleware is still uninitialised.
          if self._request_middleware is None:
            因为 load_middleware() 可能没有调用, 调用一次.
            self.load_middleware()
        except:
          # Unload whatever middleware we got
          self._request_middleware = None
          raise 
    set_script_prefix(base.get_script_name(environ))
    signls.request_started.send(sender=self.__class__) # __class__ 代表自己的类 
    try:
      # 实例化 request_class = WSGIRequest, 将在日后文章中展开, 可以将其视为一个代表 http 请求的类
      request = self.request_class(environ)
 
    except UnicodeDecodeError:
      logger.warning('Bad Request (UnicodeDecodeError)',
        exc_info=sys.exc_info(),
        extra={
          'status_code': 400,
        }
      )
      response = http.HttpResponseBadRequest()
    else:
      # 调用 self.get_response(), 将会返回一个相应对象 response<br>      ############# 关键的操作, self.response() 可以获取响应数据.     
      response = self.get_response(request)
 
    # 将 self 挂钩到 response 对象
    response._handler_class = self.__class__ 
    try:
      status_text = STATUS_CODE_TEXT[response.status_code]
    except KeyError:
      status_text = 'UNKNOWN STATUS CODE'
     # 状态码
    status = '%s %s' % (response.status_code, status_text) 
    response_headers = [(str(k), str(v)) for k, v in response.items()] 
    # 对于每个一个 cookie, 都在 header 中设置: Set-cookie xxx=yyy
    for c in response.cookies.values():
      response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
 
    # start_response() 操作已经在上节中介绍了
    start_response(force_str(status), response_headers) 
    # 成功返回相应对象
    return response

WSGIHandler 类只实现了 def __call__(self, environ, start_response), 使它本身能够成为 WSGI 中的应用程序, 并且实现 __call__ 能让类的行为跟函数一样, 详见 python __call__ 方法.

def __call__(self, environ, start_response) 方法中调用了 WSGIHandler.get_response() 方法以获取响应数据对象 response. 从 WSGIHandler 的实现来看, 它并不是最为底层的: WSGIHandler 继承自 base.BaseHandler, 在 django.core.handler 的 base.py 中可以找到: class BaseHandler(object):...

这一节服务器部分已经结束, 接下来的便是中间件和应用程序了, 相关内容会在下节的 BaseHandler 中展开. 我已经在 github 备份了 Django 源码的注释: Decode-Django, 有兴趣的童鞋 fork 吧.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python循环语句之break与continue的用法
Oct 14 Python
Django1.7+python 2.78+pycharm配置mysql数据库
Oct 09 Python
python中subprocess批量执行linux命令
Apr 27 Python
PyTorch上实现卷积神经网络CNN的方法
Apr 28 Python
对pandas将dataframe中某列按照条件赋值的实例讲解
Nov 29 Python
Flask框架 CSRF 保护实现方法详解
Oct 30 Python
python tkinter控件布局项目实例
Nov 04 Python
解决Pytorch 加载训练好的模型 遇到的error问题
Jan 10 Python
Python面向对象编程基础实例分析
Jan 17 Python
python argparse模块通过后台传递参数实例
Apr 20 Python
Python eval函数介绍及用法
Nov 09 Python
想学画画?python满足你!
Dec 24 Python
详解如何用TensorFlow训练和识别/分类自定义图片
Aug 05 #Python
详解如何从TensorFlow的mnist数据集导出手写体数字图片
Aug 05 #Python
Python获取时间范围内日期列表和周列表的函数
Aug 05 #Python
Django ORM 查询管理器源码解析
Aug 05 #Python
python实现车牌识别的示例代码
Aug 05 #Python
使用python实现滑动验证码功能
Aug 05 #Python
Django 源码WSGI剖析过程详解
Aug 05 #Python
You might like
php根据用户语言跳转相应网页
2015/11/04 PHP
Laravel 中使用简单的方法跟踪用户是否在线(推荐)
2019/10/30 PHP
jQuery中append、insertBefore、after与insertAfter的简单用法与注意事项
2020/04/04 Javascript
javascript实现div浮动在网页最顶上并带关闭按钮效果实例
2013/08/13 Javascript
js图片卷帘门导航菜单特效代码分享
2015/09/10 Javascript
基于Jquery和html5实现炫酷的3D焦点图动画
2016/03/02 Javascript
AngularJS通过$sce输出html的方法
2016/09/22 Javascript
Angular学习笔记之angular的$filter服务浅析
2016/11/12 Javascript
ES6字符串模板,剩余参数,默认参数功能与用法示例
2017/04/06 Javascript
Vue.js自定义事件的表单输入组件方法
2018/03/08 Javascript
通过一次报错详细谈谈Point事件
2018/05/17 Javascript
微信小程序云开发 搭建一个管理小程序
2019/05/17 Javascript
微信小程序图片加载失败时替换为默认图片的方法
2019/12/09 Javascript
Node.js API详解之 readline模块用法详解
2020/05/22 Javascript
vue中v-model对select的绑定操作
2020/08/31 Javascript
[03:09]2014DOTA2国际邀请赛 Mushi前队友送上祝福
2014/07/12 DOTA
[01:19:46]EG vs Secret 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
python查询sqlite数据表的方法
2015/05/08 Python
符合语言习惯的 Python 优雅编程技巧【推荐】
2018/09/25 Python
详解Python字典的操作
2019/03/04 Python
Python爬取视频(其实是一篇福利)过程解析
2019/08/01 Python
python多进程并行代码实例
2019/09/30 Python
Python3.8对可迭代解包的改进及用法详解
2019/10/15 Python
Keras框架中的epoch、bacth、batch size、iteration使用介绍
2020/06/10 Python
python批量提取图片信息并保存的实现
2021/02/05 Python
对象的序列化(serialization)类是面向流的,应如何将对象写入到随机存取文件中
2015/06/22 面试题
初任培训自我鉴定
2013/10/07 职场文书
播音主持专业个人自我评价
2014/01/09 职场文书
社区包粽子活动方案
2014/01/21 职场文书
个人贷款担保书
2014/04/01 职场文书
个人对照检查材料思想汇报(四风问题)
2014/09/25 职场文书
2014年社区工会工作总结
2014/12/18 职场文书
班主任自我评价范文
2015/03/11 职场文书
政协常委会议主持词
2015/07/03 职场文书
2015年信息技术教研组工作总结
2015/07/22 职场文书
2015年物业公司保洁工作总结
2015/10/22 职场文书