drf 02——CBV源码、APIView、Request对象源码、序列化类Serializer
CBV源码分析
# 路由层
from django.urls import path
from app01 import views
urlpatterns = [
path('books/', views.BookView.as_view()),
]
# 视图层
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
class BookView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('ok')
执行流程:
views.BookView.as_view()的执行结果 是内存地址 ---->view这个函数的内存地址
BookView.as_view() 执行as_view()方法 BookView名称空间内没有去他的父类View里找
继承了父类 就继承父类里的所有属性方法 View类里有绑定给类的方法as_view
class View:
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
return self.dispatch(request, *args, **kwargs)
return view
def dispatch(self, request, *args, **kwargs):
# 小写请求方法字符串 判断在不在列表中 'get'
if request.method.lower() in self.http_method_names:
# 在 反射 去对象中 根据字符串 取出方法或属性
# self为视图类的对象 'get' 取出方法或属性给handler
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 执行handler方法 即视图函数的get方法
return handler(request, *args, **kwargs)
执行as_view方法 返回view 即views.BookView.view
路由匹配成功就会执行view方法 view(request) 返回self.dispatch(request, *args, **kwargs)
执行dispatch 发送什么请求 就会执行视图类中请求名字的方法
APIView的基本使用
前面讲的是继承View的CBV
现在要使用drf 写的也都是cbv 但要继承的是drf提供的视图类 APIView
其实看名字就知道APIView继承的View 但此时名字查找顺序就发生了改变
首先先注册drf drf是个app 需要注册
INSTALLED_APPS = [
...
'rest_framework'
]
'注意点':
1.app后要有, 2.不要使用三引号加注释
补充:django项目中app的作用
django是一个大而全的框架 内置了很多app
INSTALLED_APPS = [
'django.contrib.admin', # 后台管理,系统自带后台管理admin
'django.contrib.auth', # 权限管理--》生成6张表
'django.contrib.contenttypes', # 对所有app的表进行记录的
'django.contrib.sessions', # session功能--》django-session表---》app
'django.contrib.messages', # django消息框架---》flask的闪现
'django.contrib.staticfiles', # 静态资源
'app01.apps.App01Config',
'rest_framework', # 一定不要忘了注册
]
视图层
以后不再写django原生的响应方式:render,HttpResponse,Redirect,JsonResponse
drf提供了Response响应 能够存放字符串,字典,列表 (HttpResponse+JsonResponse结合体)
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
# return HttpResponse('fu*k u')
return Response('super mother fu*k')
由于继承了APIView 将会执行APIView的as_view,dispatch
APIView执行流程分析
流程分析:
path('books/', views.BookView.as_view())
views.BookViwe.as_view()的执行结果,是view这个函数的内存地址 即views.BookView.view
现在的as_view不再是django原生View的as_view
现在是去APIView内找as_view
路由写法不变--------执行发生了变化
请求来了------>路由匹配成功------>执行函数view(request)
# 派生方法:子类中重写父类中的方法或者新写方法 叫派生
# 派生类也就是子类
def as_view(cls, **initkwargs): # as_view是django的View的派生方法
# 这个view就是原生django中View类的view,还是原来的view
view = super().as_view(**initkwargs) # super()子类调用父类
# csrf_exempt--->去除了所有的csrf---》csrf中间件---》post提交数据,如果不注释---》协带csrf---》以后,无论中间件是否注释,都不需要带了
# csrf_exempt装饰器装饰视图函数--->本质跟csrf_exempt(view)一毛一样
# 它就是装饰器的本质:把被装饰的函数当做参数,传入装饰器函数,返回值赋值给被装饰的函数
return csrf_exempt(view)
此时 1.view还是原来的view 2.以后不用管csrf了
dispatch也不再是原生View的dispatch,而是drf的APIView的dispatch
def dispatch(self, request, *args, **kwargs):
# 包装了新的request对象--》以后视图类中用的request对象,就是新的request
request = self.initialize_request(request, *args, **kwargs)
try: # 捕获异常
# 内部执行了三大认证:认证(登陆认证),频率(1分钟只能访问接口3次),权限(普通用户不能访问,超级用户才能访问)
self.initial(request, *args, **kwargs)
# 原来dispatch的代码,重写了一下---》执行视图函数
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)
# 包装了response对象,响应对象,浏览器看到好看的样子,postman只看到json
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
重点
1.drf: 包装了新的request对象(drf的Request的对象) 不再是django的request对象
# rest_framework.request.Request 以后新的request
# django.core.handlers.wsgi.WSGIRequest django原来的request
2.在执行那个视图函数之前 执行了三大认证
3.处理了全局异常 执行三大认证期间,执行视图函数期间,如果出了错,都能统一处理
4 包装了响应对象
Request对象源码分析
以后视图类中使用的request对象,是rest_framework.request.Request的对象
class Request:
# 1 把老的request放到了新的request的_request属性了
# 新的request--》request._request 是老的
def __init__(self, reqeust...):
self._request = request(这个request是老的)
# 2 以后新的request用起来跟原来一样用
# 取出原来老request的属性,以下方法取,麻烦
request._request.POST
request._request.GET
request._request.method
# 重写了__getattr__ 魔法方法,. 拦截 --》对象.属性如果属性不存在,触发这个方法执行
def __getattr__(self, attr):
try:
# 通过反射 去拿老reqeust的属性或方法
return getattr(self._request, attr) # self._request为老的request
except AttributeError:
return self.__getattribute__(attr)
# 3 新的request有个data方法,包装成了数据属性
-前端无论什么编码方式传得body体中的数据,都从request.data中取,当字典用即可
-原生djagno,如果是formdata,urlencoded是从POST中取,如果是json,从body中取出来自己转
# 4 新的request有个query_params方法,包装成了数据属性
-就是原来老的request的GET属性
@property
def query_params(self):
return self._request.GET
# 5 上传文件,跟之前一样用,但是人家重写了
重点
1. 老的request是新的request._request
2. 跟原来一样用
3. body提交的数据都从request.data中取
4. 请求地址中的数据都从request.query_params中取
序列化类Serializer的使用
序列化组件----一个类Serializer,可以完成下面的事情
-
序列化,把模型对象(book,queryset)转换成字典,经过drf的response以后变成json字符串
-
反序列化,把客户端发送过来的数据(前端json格式字符串),经过request.data以后变成字典
序列化器可以把字典转成模型,存到数据库
- 反序列化,完成数据校验功能(前端传入的数据,长短。是否邮箱等等进行校验)
序列化的功能:表中数据序列化后 以json格式返回给前端
路由
path('books/', views.BookAPIView.as_view()),
视图层
from .models import Book
from .serializer import BookSerializer
class BookAPIView(APIView):
def get(self,request):
# 取出所有图书的queryset对象
books=Book.objects.all()
# 借助序列化类 写一个序列化类
# 类实例化时:instance:要序列化的对象 many:True 多条 先记着这两个参数
ser=BookSerializer(instance=books,many=True)
# ser.data 完成了序列化
print(ser.data) # 把qs对象,转成了字典,根据序列化类中你写的字段转的
return Response(ser.data)
序列化类
from rest_framework import serializers
class BookSerializer(serializers.Serializer): # 继承Serializer
# 写要序列化的字段 不要的不写
name = serializers.CharField() # 字段类,跟models中一一对应
price = serializers.IntegerField()
publish = serializers.CharField()
author = serializers.CharField()
序列化类常用字段和字段参数
# 字段类和字段属性
### 字段类:跟models一一对应,但是比它多
# BooleanField
# NullBooleanField
# CharField
# EmailField
# RegexField
# SlugField
# URLField
# UUIDField
# IPAddressField
# IntegerField
# FloatField
# DecimalField
# DateTimeField
# DateField
# TimeField
# ChoiceField
# FileField
# ImageField
------ 以上都是models有的----下面是serializer独有的---
# ListField
# DictField
#### 字段属性--->写在字段类中的---》干啥用?反序列化校验用的!!!!
## 选项参数
# CharField
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
# IntegerField
max_value 最小值
min_value 最大值
# 通用参数:
### 重点讲
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
error_messages 包含错误编号与错误信息的字典

浙公网安备 33010602011771号