上图是Django基础逻辑图

①Django里封装了WSGI模块,用于循环监听socket链接,当客户端发送WEB请求,wsgi就会与客户端建立连接,从而发送数据。

②socket通信建立以后,在用户请求进入Django之前,会经历一层中间件的筛选:

具体流程如下:

1.process_request

2.peocess_view

3.process_exception

4.process_template_response

5.process_response

其中3,4环节我的理解是互斥的,当出现exception,就不会在出现整场渲染的页面,process_template_response也就不会执行,如果出现了渲染页面那么也就意味着异常没有被触发。

③URL是Django的路由匹配(其表现形式是Djangox项目中的views.py文件,通过正则匹配按照用户请求的url地址寻找与之对应的view视图函数)。

注意:由于路由匹配是按照列表遍历的形式自上而下匹配的,所以如果陈旭里路由匹配定义母虎不清,会出现匹配不到或者无法匹配的情况。

④当匹配到相应的视图函数,对于动态页面就会从后端的数据库里获取前端页面需要的数据,传递方式为视图函数中return值中附加的字典形式。

⑤由于页面渲染为相对比较复杂的一个过程,所以我们将页面的渲染放在Template模板中,具体的应用方式为模板语言的使用,在之后的博客中,会详细说明,今天主要叙述wsgi,middleware,url

一,wsgi

新建Django项目,在项目文件夹中,会有wsgi.py文件。

代码如下;

"""WSGI config for 数据库创建 project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, seehttps://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/"""

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "数据库创建.settings")

application = get_wsgi_application()

这是Django内部定义的一个函数,ctrl+左键点击进入该函数
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.    """    django.setup(set_prefix=False)    return WSGIHandler()

我们注意到return值为WSGIHandler()

继续ctrl+左键点击进入
class WSGIHandler(base.BaseHandler):request_class = WSGIRequest

    def __init__(self, *args, **kwargs):        super(WSGIHandler, self).__init__(*args, **kwargs)        self.load_middleware()

    def __call__(self, environ, start_response):

        set_script_prefix(get_script_name(environ))        signals.request_started.send(sender=self.__class__, environ=environ)        request = self.request_class(environ)        response = self.get_response(request)

        response._handler_class = self.__class__

        status = '%d %s' % (response.status_code, response.reason_phrase)        response_headers = [(str(k), str(v)) for k, v in response.items()]        for c in response.cookies.values():            response_headers.append((str('Set-Cookie'), str(c.output(header=''))))        start_response(force_str(status), response_headers)        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):            response = environ['wsgi.file_wrapper'](response.file_to_stream)        return response

在看他的父类之前,我们先进入request_class = WSGIRequest
class WSGIRequest(http.HttpRequest):  我们可以看出这是另外一个继承过来的类

不死不休,进入这个类(http.HttpRequest)
class HttpRequest(object):    """A basic HTTP request."""

    # The encoding used in GET/POST dicts. None means use default setting.    _encoding = None    _upload_handlers = []

    def __init__(self):        # WARNING: The `WSGIRequest` subclass doesn't call `super`.        # Any variable assignment made here should also happen in        # `WSGIRequest.__init__()`.

self.GET = QueryDict(mutable=True)        self.POST = QueryDict(mutable=True)        self.COOKIES = {}        self.META = {}        self.FILES = MultiValueDict()

        self.path = ''        self.path_info = ''        self.method = None        self.resolver_match = None        self._post_parse_error = False        self.content_type = None        self.content_params = None
这时我们已基本可以看到我们请请求头的一些信息,这就是我们给wsgi指定的一些请求头信息,终于,我们找到了比较原始的socket连接部分,开不开心,激不激动?
WSGIHandler是Django定义的一个类(该类继承base.BaseHandler),老规矩,点击进入父类
由于父类代码实在太长了,这里我只截取父类的基本信息外加文字注释
class BaseHandler(object):

    def __init__(self):        self._request_middleware = None        self._view_middleware = None        self._template_response_middleware = None        self._response_middleware = None        self._exception_middleware = None        self._middleware_chain = None  
  def load_middleware(self):      该函数主要是读取settings配置文件中的中间件信息,并利用类的反射执行相应的中间件函数。

其实从这两个类的执行我们基本可以看出来Django程序的执行顺序。

signal在程序初期,就已开启监听状态,这也就是后来为什么我们写自定义信号会写在__init__文件中,因为信号的监听应该体现在程序的整个生命周期中

request变量的初始化,这就是我们在发送接收请求时赖以使用的变量,他封装了我们web请求的大部分信息。

Cookie的使用,在程序初期,我们使用Cookie纪录我们每一次访问的标识位

一切我们在Django中利用到的神奇变量,全部都在我们神奇的类中。

好,接下来我们聊聊中间件!

因为我们的settings配置文件里都是字符串格式的中间件,这时,我们就可以把某一个字符串copy一下,按照他的路径去引入一下,这时我们就可以看到Django最初的中间件是怎么定义的了

这里我随便找了一个中间件做实验哈。
from django.middleware.security import SecurityMiddlewareMIDDLEWARE = ['django.middleware.security.SecurityMiddleware',    'django.contrib.sessions.middleware.SessionMiddleware',    'django.middleware.common.CommonMiddleware',    'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',]
看到我是怎么import的了吗?非常简单哦,哈哈

老规矩,点进去这个东东看看他到底是什么????
class SecurityMiddleware(MiddlewareMixin):    def __init__(self, get_response=None):        self.sts_seconds = settings.SECURE_HSTS_SECONDS        self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS        self.sts_preload = settings.SECURE_HSTS_PRELOAD        self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF        self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER        self.redirect = settings.SECURE_SSL_REDIRECT        self.redirect_host = settings.SECURE_SSL_HOST        self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]        self.get_response = get_response

    def process_request(self, request):        path = request.path.lstrip("/")        if (self.redirect and not request.is_secure() and                not any(pattern.search(path)                        for pattern in self.redirect_exempt)):            host = self.redirect_host or request.get_host()            return HttpResponsePermanentRedirect(                "https://%s%s" % (host, request.get_full_path())            )

    def process_response(self, request, response):        if (self.sts_seconds and request.is_secure() and                'strict-transport-security' not in response):            sts_header = "max-age=%s" % self.sts_seconds            if self.sts_include_subdomains:                sts_header = sts_header + "; includeSubDomains"            if self.sts_preload:                sts_header = sts_header + "; preload"            response["strict-transport-security"] = sts_header

        if self.content_type_nosniff and 'x-content-type-options' not in response:            response["x-content-type-options"] = "nosniff"

        if self.xss_filter and 'x-xss-protection' not in response:            response["x-xss-protection"] = "1; mode=block"

        return response
of course,这又是一个继承过来的类,那么我们再去看看他的父类吧
class MiddlewareMixin(object):    def __init__(self, get_response=None):        self.get_response = get_response        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):        response = None        if hasattr(self, 'process_request'):            response = self.process_request(request)        if not response:            response = self.get_response(request)        if hasattr(self, 'process_response'):            response = self.process_response(request, response)        return response
这时,我打算用我最浅薄的理解去讲述我们的中间件,在继承MiddlewareMixin父类的基础上,我们自己定义一个类,要注意,我们自定制的中间件想要在哪一个部分做限制

就在哪一个部分定义我们的类方法:

1.process_request

2.peocess_view

3.process_exception

4.process_template_response

5.process_response

这五个方法你随便定义,如果你只是想要个好看,那么ok,只在函数体内写pass就可以了

另外,中间件需要在哪里定义呢?答案是想写哪里写哪里?只要你在setting配置文件中引入中间件类的py文件,并且在你的settings中多加一个或者几个字符串就可以了。

是不是特别方便简单呢?

哦,接下来是url

那么,请打开Django中的urls.py文件,我们来分析一下。

from django.conf.urls import urlfrom django.contrib import adminfrom 数据库.views import *

urlpatterns = [    url(r'^admin/', admin.site.urls),    url(r'^add/', add),]

最简单的理解就是把urlpatterns遍历一遍,根据规定好的正则匹配字符串去匹配客户端请求发来的url地址,匹配到就会执行其对应的view视图函数。

不过为了对自己负责,还是分析一下,虽然这只是作业。

点金进入url
def url(regex, view, kwargs=None, name=None):    if isinstance(view, (list, tuple)):        # For include(...) processing.urlconf_module, app_name, namespace = view        return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)    elif callable(view):        return RegexURLPattern(regex, view, kwargs, name)    else:        raise TypeError('view must be a callable or a list/tuple in the case of include().')
我们可以看到固定的位置参数有两个。一个是正则匹配表达式,一个是对应的视图函数。

要注意,这时我们匹配的view参数是按照列表或者元组的方式去获取的,当匹配成功就会自行分割,那么我们最终的函数体是哪一个呢???

经过我的思考,他就是namespace,是不是一个非常熟悉的名字,名称空间,我们知道python的每一个变量,每一个韩树明,每一个列名,都是储存在我们的名称空间中,通过关系映射,我们

可以找到他对应的值,从而执行我们的函数体,得到最终结果。

也许大家还注意到,我紫色标注的内容,这又是一个类,不行了,我的懒癌又犯了,今天就不写啦,哈哈




 

转载于:https://www.cnblogs.com/575dsj/p/7623704.html

Django(wsgi,middleware,url源码剖析)相关推荐

  1. Django Rest Framework 部分源码剖析

    转载于:https://www.cnblogs.com/xintiao-/p/10079550.html

  2. 源码剖析Django REST framework的认证方式及自定义认证

    源码剖析Django REST framework的认证方式 由Django的CBV模式流程,可以知道在url匹配完成后,会执行自定义的类中的as_view方法. 如果自定义的类中没有定义as_vie ...

  3. Django Rest Framework源码剖析(二)-----权限

    一.简介 在上一篇博客中已经介绍了django rest framework 对于认证的源码流程,以及实现过程,当用户经过认证之后下一步就是涉及到权限的问题.比如订单的业务只能VIP才能查看,所以这时 ...

  4. Django Rest Framework源码剖析(七)-----分页

    一.简介 分页对于大多数网站来说是必不可少的,那你使用restful架构时候,你可以从后台获取数据,在前端利用利用框架或自定义分页,这是一种解决方案.当然django rest framework提供 ...

  5. CBV与FBV的区别/CBV源码剖析

    FBV与CBV # 针对于视图函数(views.py),视图函数编写逻辑既可以使用函数(FBV)也可以使用类(CBV)来编写. 区别展示: login.html <h1>GET请求< ...

  6. Mongoose源码剖析:外篇之web服务器

    引言 在深入Mongoose源码剖析之前,我们应该清楚web服务器是什么?它提供什么服务?怎样提供服务?使用什么协议?客户端如何唯一标识web服务器的资源?下面我们抛开Mongoose,来介绍一个we ...

  7. Spring源码剖析——Bean的配置与启动

    IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...

  8. cmd怎么运行http_Scrapy源码剖析(二)Scrapy是如何运行起来的?

    阅读本文大约需要 15 分钟.本文章代码较多,如果手机端阅读体验不好,建议先收藏后在 PC 端阅读. 在上篇文章:Scrapy源码剖析(一)架构概览,我们主要从整体上了解了 Scrapy 的架构和数据 ...

  9. tomcat(12)org.apache.catalina.core.StandardContext源码剖析

    [0]README 0)本文部分文字描述转自 "how tomcat works",旨在学习 "tomcat(12)StandardContext源码剖析" 的 ...

  10. python源码剖析 豆瓣_在数据分析师的分析中豆瓣的书那些值得读

    最近总是有人问我有什么书好推荐看看,特烦.但是看到那么多人问,看来挺多人有这个需求,便想了一下,如何通过数据分析找到值得看的书.通过爬取某个标签例如产品,运营获取对应已经打了标签的书,获取书对应的评分 ...

最新文章

  1. 代码规范指南:怎样写才能干净整洁
  2. 程序员别只顾着敲代码了,看看吧
  3. memcached安装配置
  4. 重新精读《Java 编程思想》系列之向上转型与向下转型
  5. 程序员面试题精选100题(26)-和为n连续正数序列[算法]
  6. 安装nvm管理多版本nodejs
  7. 通过SQL Server操作MySQL的步骤和方法
  8. 利用 git 提交代码、git 简单使用(拉取、推送、分支、合并)
  9. C#LeetCode刷题之#453-最小移动次数使数组元素相等(Minimum Moves to Equal Array Elements)
  10. Luogu P1311 选择客栈(前缀和)
  11. 戴明理论、朱兰理论、克鲁斯比理论和田口玄一理论
  12. 国家开放大学2021春1078复变函数题目
  13. 为什么数据库用B+树(3条法则需记牢)
  14. JAVAWEB学习总结
  15. 中国第一代技术网红,阿里云P10技术专家褚霸:我只是一个程序员 。
  16. 使用 conda uninstall xxx时,一直卡在 Collecting package metadata (repodata.json)
  17. 反向代理为何叫反向代理?(含案例)
  18. CentOS7 网络安装版本 设置基础软件仓库出错
  19. LVGL8.2学习笔记
  20. favicon自动获取_wordpress网站友情链接页面使用DNSPod自动获取网站favicon图标教程...

热门文章

  1. flash debug版本
  2. 采云端采云链:从订单协同到采购供应链,让采购供应链互联互通
  3. linux 培训感谢信,应用文(考试)应用文(考).doc
  4. 计算机用户名,账户名更改
  5. 配合字体图标的搜索框
  6. win7 计算机设置命令,win7系统如何设置自动关机?
  7. Centos7重置用户密码
  8. linux用命令行快速切换目录
  9. [基于kk搭建k8s和kubesphere] 1 概念和文档
  10. 【Leetcode刷题篇】Leetcode714 买卖股票的最佳时机含手续费