一、一个请求来到Django 的生命周期
  • FBV 不讨论

  • CBV:

    请求被代理转发到uwsgi:

    开始Django的流程:

    首先经过中间件process_request (session等)

    然后:url --- > Xxx.as_view() 根据url映射到对应业务逻辑类 --->process_view (csrf等)

     

    业务逻辑类中:

    as_view() -- > view ---> dispatch() 通过映射调用请求的方法在业务逻辑中的对应处理函数

    (如post、put、delete等)

 

1.2 CBV源码解析
  • 自己的业务逻辑类:MyView 继承View

  • 没有as_view() 方法,将会去父类View找as_view

class MyView(View):

    def get(self, request):
#处理业务逻辑,返回response
pass def post(self, request):
pass def put(self, request):
pass def delete(self, request):
pass

 

1.2.2 View源码中:as_view() 方法被调用
  • 查看as_view 方法源码:作者省略了部分,只留下了关键部分,并做了注释
class View:
...
@classonlymethod
def as_view(cls, **initkwargs):
... def view(request, *args, **kwargs):
...
return self.dispatch(request, *args, **kwargs) #调用父类的dispatch() 方法
... return view #返回内部定义的view 方法

这儿可以看见:

1.  as_view()方法被调用,

2.  内部回返回定义的view 方法,

3.  view方法中调用了 dispatch() 方法

4.  如果自己的类没有重写dispatch 方法的话,将会调用父类View类的 dispatche() 方法

 

1.2. 查看dispatch方法
  • dispatch方法中:作者省略了部分,只留下了关键部分,并做了注释
class View:
...
def dispatch(self, request, *args, **kwargs):
...
#request.method中保存了客户端解析出来的请求方法,如:GET/POST等
if request.method.lower() in self.http_method_names: #通过映射找到请求对应我们自己的业务逻辑处理函数
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) #并调用该业务逻辑函数处理结果,将结果返回
  • 注意:request.method 保存着解析出来的请求行第一个数据(GET URL HTTP1.1)如:GET

可以看见:

1.  if判断客户端请求的方法是否是,http协议(Django)自己支持的

2.  handler = getattr(self, request.method.lower(), self.http_method_not_allowed)

    将请求方法小写,然后在自己的业务类中映射到对应处理函数,如果没有报错

3.  return handler(request, *args, **kwargs)

    并调用该业务逻辑函数处理结果,将结果返回

 

二、rest_framework APIView 流程解析

先看一个图:给出大致流程

 

2.2 APIView中请求流程
  • 同上:请求通过URL 匹配到继承APIView的自己的业务逻辑类。
class APIView(View):
...
parser_classes = api_settings.DEFAULT_PARSER_CLASSES #默认解析类
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #默认认证类
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES #默认限流类
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES #权限类
...
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS #版本控制获取类 ... @classmethod
def as_view(cls, **initkwargs):
...
view = super(APIView, cls).as_view(**initkwargs) #继承父类as_view方法
view.cls = cls
view.initkwargs = initkwargs
...
return csrf_exempt(view) #返回父类view
...
def get_parsers(self):
"""
获取到上面4. 第一步initialize_request函数封装request过程中一并生成封装的解析器对象
"""
return [parser() for parser in self.parser_classes] def get_authenticators(self):
"""
同理身份认证对象
"""
return [auth() for auth in self.authentication_classes] def get_permissions(self):
"""
同理权限对象
"""
return [permission() for permission in self.permission_classes] def get_throttles(self):
"""
同理限流(访问频率控制对象)
"""
return [throttle() for throttle in self.throttle_classes] def perform_authentication(self, request):
... #这里面真正认证 def check_permissions(self, request):
... #这里面检查权限 def check_throttles(self, request):
... #这里面限流 def determine_version(self, request, *args, **kwargs):
... #这里面获取版本 def initialize_request(self, request, *args, **kwargs):
"""
被dispatch调用,封装request,并调用上述函数生成相应对象封装到request对象中
"""
parser_context = self.get_parser_context(request) return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
) def initial(self, request, *args, **kwargs):
...
被dispatch调用,在里面初始化获取版本,认证、权限检查、访问控制等 # Determine the API version, if versioning is in use.
#处理版本问题,调用 determine_version方法
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
#3.在这儿实现认证
self.perform_authentication(request)
#4.权限检查
self.check_permissions(request)
#5.访问频率控制 ... def dispatch(self, request, *args, **kwargs):
...
self.args = args
self.kwargs = kwargs
##############################################################
# 1.封装request
request = self.initialize_request(request, *args, **kwargs)
##############################################################
self.request = request
self.headers = self.default_response_headers # deprecate? try:
##############################################################
#2.认证
self.initial(request, *args, **kwargs)
##############################################################
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response

如下步骤对应上述省略部分的源代码去找:

1. 找as_view()函数

第一步自己业务逻辑类中:没有,

第二步父类-APIView中:找到as_view方法,开始调用

2. APIView继承了View,APIView的as_view函数继承了父类as_view:如下为源码

view = super(APIView, cls).as_view(**initkwargs) #继承父类的as_view

view.cls = cls #把自身封装进去

view.initkwargs = initkwargs #将参数初始化

return csrf_exempt(view) #返回view

可以看见封装了一次as_view方法,将自身cls (APIView)一起封装到了view中

并返回

3. 通过上面1-2 知道:继承请求进入后会调用返回的view方法,然后在self中找dispatch方法,

第一步自己的业务逻辑类中:没有dispatch

第二步父类APIView中:找到dispatch方法,开始调用

4. APIView的dispatch 函数中:

第一步:request = self.initialize_request(request, *args, **kwargs) 封装了一次request

 

initialize_request函数内如下:

return Request(

request, #原生request

parsers=self.get_parsers(), #解析器

authenticators=self.get_authenticators(), #身份验证器

negotiator=self.get_content_negotiator(),

parser_context=parser_context

)

第二步:self.initial(request, *args, **kwargs) 开始初始化认证

 

initial函数内:

1)获取版本,版本处理类实例。并封装到request中

version, scheme = self.determine_version(request, *args, **kwargs)

request.version, request.versioning_scheme = version, scheme

 

2)身份(登录)认证啥的

self.perform_authentication(request)

 

3)权限管理

self.check_permissions(request)

 

4)限流控制(访问频率控制)

self.check_throttles(request)

 

2.2.3 上述总结
  1. 首先找dispatch 函数(APIView类中)

  2. dispatch中:

    调用了self.initialize_request 函数封装request

  3. 接着2的dispatch中initialize_request 函数

    查看APIView中的initialize_request 函数

    调用了:get_parsers()、get_authenticators() 等

    封装了一堆解析器类实例、认证类实例啥的

    可自己去看(这些类使用默认配置,APIView 一开头下面一堆配置就是)

    这些类也可以自己写,配置到自己的业务逻辑类中,或者settings.py中作为全局配置(下面在讲)

  4. 接着2的dispatch中initial函数

    版本获取:

    version, scheme = self.determine_version(request, *args, **kwargs)

    request.version, request.versioning_scheme = version, scheme

    实现认证

    self.perform_authentication(request)

    权限检查

    self.check_permissions(request)

    访问频率控制

    self.check_throttles(request)

 

三、常用的解析、认证、权限、访问频率控制源码及解析

from rest_framework.views import APIView #继承类路径

from rest_framework import request #dispatch中initialize_request封装的request对象

from rest_framework.parsers import JSONParser, FormParser, FileUploadParser #不同解析器

from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning #两种版本获取器

from rest_framework.authentication import BaseAuthentication #登录验证

from rest_framework.permissions import BasePermission #权限

from rest_framework.throttling import SimpleRateThrottle #节流

from rest_framework import exceptions #错误

Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析的更多相关文章

  1. Django生命周期,FBV,CBV

    一. Django生命周期 首先我们知道HTTP请求及服务端响应中传输的所有数据都是字符串,在Django中,当我们访问一个的url时,会通过路由匹配进入相应的html网页中.Django的请求生命周 ...

  2. 学以致用三十三-----django生命周期

    听了讲解django的视频后,受益匪浅,每个知识点老师都会总结整理.学会总结,存为己用. django生命周期弄明白后,对于整个django的框架会有一个清晰的了解.先上图 1.客户端发送请求,在dj ...

  3. 用户增删改查 django生命周期 数据库操作

    一 django生命周期 1 浏览器输入一个请求(get/post)2 响应到django程序中3 执行到url,url通过请求的地址匹配到不同的视图函数4 执行对应的视图函数,此过程可以查询数据库, ...

  4. django生命周期和事件委派

    这是事件委派如果不用事件委派   直接绑定的话,新添加的按钮不会有删除或者编辑的功能 上面是事件委派的代码 新添加的编辑按钮可以弹出123 django生命周期: 这是Django的生命周期 首先会通 ...

  5. Django框架(三)-- orm增删改查、Django生命周期

    一.orm介绍 1.什么是orm ORM即Object Relational Mapping,全称对象关系映射. 2.使用orm的优缺点 优点: 不用写SQL语句 开发效率高 缺点: SQL的效率低 ...

  6. Django框架(三)—— orm增删改查、Django生命周期

    目录 orm增删改查.Django生命周期 一.orm介绍 二.orm增删改字段 三.Django生命周期 orm增删改查.Django生命周期 一.orm介绍 1.什么是orm ORM即Object ...

  7. 【Cocos2d-x 3.x】 场景切换生命周期、背景音乐播放和场景切换原理与源码分析

    大部分游戏里有很多个场景,场景之间需要切换,有时候切换的时候会进行背景音乐的播放和停止,因此对这块内容进行了总结. 场景切换生命周期 场景切换用到的函数: bool Setting::init() { ...

  8. Django生命周期

    以下信息是个人理解所得,如要转载,请注明转载处! 生命周期?很多人会问生命周期是什么?Django也有生命周期吗?他就是一个框架呀. 我们先来说一说一个西瓜的生命周期,一个西瓜刚开始只是一个种子,种到 ...

  9. Django(十一)请求生命周期之CBV与FBV

    https://www.cnblogs.com/yuanchenqi/articles/8715364.html FBV FBV(function base views) 就是在视图里使用函数处理请求 ...

随机推荐

  1. .Net语言 APP开发平台——Smobiler学习日志:如何在手机中调用邮件发送接口

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 一.目标样式 我们要实现上图中的效果,需要如下的操作: 二.发送邮件代码 VB: Pr ...

  2. MTF测试图卡规格

    1.Imatest Chart Finder计算图卡大小 测试camera MTF时,需要知道所需要的图卡的大小,Imatest提供了一个网页,只要输入sensor的像素, 镜头的视场角,还有镜头到图 ...

  3. Predicate--入门简介

    说明:表示定义一组条件并确定指定对象是否符合这些条件的方法.此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素. var predicate = new Predicate&l ...

  4. Java开发笔记(二十三)数组工具Arrays

    数组作为一种组合形式的数据类型,必然要求提供一些处理数组的简便办法,包括数组比较.数组复制.数组排序等等.为此Java专门设计了Arrays工具,该工具包含了几个常用方法,方便程序员对数组进行加工操作 ...

  5. 【.Net Core】获取绝对路径、相对路径

    一.绝对路径 1.获取应用程序运行当前目录Directory.GetCurrentDirectory(). System.IO命名空间中存在Directory类,提供了获取应用程序运行当前目录的静态方 ...

  6. .NET平台下使用MongoDB入门教程

    适合人群:完全没有接触MongoDB或对MongoDB有一点了解的C#开发人员.因为本文是一篇入门级的文章. 一.了解MongoDB  MongoDB是一个基于分布式文件存储的数据库.由C++语言编写 ...

  7. 关于如何使用xposed来hook某支付软件

    由于近期有业务上的需要,所以特地花时间去研究了一下如何使用hook技术.但是当我把xposed环境和程序编写完成时,突然发现手机上的某个支付软件无法使用了.这个时候我意识到,应该是该软件的安全机制在起 ...

  8. 智能POS如何获取日志&数据库文件

    使用Teamviewer连接安卓机器,文件传输 ================================================================== 智能POS查看数据 ...

  9. Windows Server 2016-查询并导出固定时间段创建AD用户

    生产环境中往往我们有各式各样的需求,例如快速查询某段时间创建用户,或批量导出固定时间段创建用户列表,具体操作如下: $date=Get-Date $oldday=(Get-Date).AddDays( ...

  10. Unity ECS 视频笔记

    视频摘要 本文视频资料:使用Entity Component System开发<快乐的Minecraft>游戏 使用Unity2018及以上版本才有ECS功能. 本文是看视频的一些摘要. ...