1.反序列化类校验部分源码分析(了解)

1.当我们在视图类中生成一个序列化类对象ser,并且用ser.is_valid()是就会执行校验,校验通过返回True,不通过返回False。首先对象ser和序列化类中都没有方法is_valid()。
然后我们去其父类Serializer中找,也没找到,再去其父类BaseSerializer中找,找到了方法is_valid():

2.关键语句在于:self._validated_data = self.run_validation(self.initial_data)
self是序列化类BookSerializer的对象,从头开始找方法run_validation。此时我们不能按ctrl点run_validation方法,因为这样找到的是其父类fields中的run_validation。但是在BookSerializer对的父类Serializer中就可以找到名字run_validation。

3.可以发现在异常捕获中看到了我们之前见过的全局钩子名字:validate。所以当我们用ser点is_valid时会触发全局钩子进行校验。

4.value = self.to_internal_value(data)这一步是在进行局部钩子的校验。还是重头开始查找名字to_internal_value,最终在类Serializer中找到了名字to_internal_value:

    def to_internal_value(self, data):
# fields是一个个字段名对象,field是字段名对象
for field in fields:
# 如果对象ser或其父类(BookSerializer)中有'validate_' + field.field_name的名字,例如validate_name,那么此时validate_method就是例如validate_name。
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
# validate_method是validate_name,validated_value就是待校验的某个字段名,这也是为什么我们在局部钩子要上传字段名。
validated_value = validate_method(validated_value)
except ValidationError as exc:
# 如果有错误将每个字段名对应的错误添加到错误信息当中。
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value) if errors:
raise ValidationError(errors) return ret
"""
面向对象中名字的查找顺序:每一次对象查找名字都要从自身的名称空间中查找,然后再到类名称空间,再到父类名称空间。
"""

2.断言

源码中大量使用try和断言:
assert后面跟的语句如果成立,就会执行下面的语句;不成立则会马上抛出异常。但是异常信息无法编辑。
assert isinstance(111,int)
print('111是整形') # 111是整形 assert isinstance(111,str)
print('111是整形') # 报错:AssertionError

3.drf请求

1.Request能够解析的前端传入的编码格式
如果我们只想接收前端发送的json格式的数据,不接受其他形式发送的数据,我们需要做如下设置:
方式一:局部配置:在继承自APIView及其子类的视图类中配置
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser class BookView(APIView):
parser_classes = [JSONParser,]
def post(self,request):
print(request.data)
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'})
else:
return Response({'code':101,'msg':ser.errors})

	方式二:全局配置:在settings中设置,会影响全局,如果想禁用掉哪个提交方式,只需要注掉就可以。
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
# 'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
"""
如果我们在全局配置了一种,部分视图函数需要三种,我们只需要在视图函数配置三种发送方式。因为配置查找顺序是:先从视图类自身查找,再到drf配置中找,再去drf默认配置中查找。
""" 2.Request类中的方法:
data,__getattr__,query_params

4.drf响应

drf响应,如果使用浏览器会好看一些,使用postman只能拿到json数据。

方式一:在视图类中写(局部配置)
-两个响应类---》找---》drf的配置文件中找--》两个类
-from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,] 方式二:在项目配置文件中写(全局配置)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
"""
优先使用视图类中的配置,其次使用项目匹配,最后使用那个内置的配置。
"""

5.Response源码属性或方法

当我们进到Response源码中发现有以下参数:
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
data:是我们返回给前端的数据,可以是字典、列表、字符串。我们之前写的ser.data就是data的内容。
status:响应状态码,默认是200,可以手动定义数字,也可以通过导模块来使用drf内部定义的响应状态码:
from rest_framework.status import HTTP_201_CREATED

template_name:了解即可,修改响应模板的样子
content_type:响应编码格式,一般不动
headers:响应头

"""
在Http四件套中如何添加响应头?
def indexfunc(request):
obj = HttpResponse('hhh') 先生成一个HttpResponse的对象
obj['msg'] = 'success' 给对象添加键值对
return obj
"""

6.视图组件介绍及两个视图基类

1.APIView跟之前的View区别
传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
视图方法可以返回REST framework的Response对象-
任何APIException异常都会被捕获到,并且处理成合适的响应信息;
在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制 2.APIView类属性:
renderer_classes # 响应格式
parser_classes #能够解析的请求格式
authentication_classes#认证类
throttle_classes#频率类
permission_classes#权限类 3.APIView+ModelSerializer+Resposne写5个接口:
serializer.py:
from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','price','publish','authors','publish_detail','author_list']
extra_kwargs = {
'name':{'max_length':8},
'publish_detail':{'read_only':True},
'author_list':{'read_only':True},
'publish':{'write_only':True},
'authors':{'write_only':True}
} def validate_name(self,name):
if name.startswith('s'):
raise ValidationError('书名不能以s开头')
else:
return name models.py:
from django.db import models class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32) publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') @property
def publish_detail(self):
return {'name':self.publish.name,'addr':self.publish.addr} @property
def author_list(self):
l = []
for author_obj in self.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32) class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11) views.py:
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.models import Book
from .serializer import BookSerializer class BookView(APIView):
def get(self,request):
book_queryset = Book.objects.all()
ser = BookSerializer(instance=book_queryset,many=True)
return Response(ser.data) def post(self,request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功','result':ser.data})
else:
return Response({'code':101,'msg':ser.errors}) class BookDetailView(APIView):
def get(self,request,pk):
book_obj = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book_obj)
return Response(ser.data) def put(self,request,pk):
book_obj = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book_obj,data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'修改成功','result':ser.data})
else:
return Response({'code':101,'msg':ser.errors}) def delete(self,request,pk):
Book.objects.filter(pk=pk).delete()
return Response({'code':100,'msg':'删除成功'}) urls.py:
from django.contrib import admin
from django.urls import path
from app01 import views urlpatterns = [
path('admin/', admin.site.urls),
path('books/',views.BookView.as_view()),
path('books/<int:pk>/',views.BookDetailView.as_view())
]

7.基于GenericAPIView写接口

1.GenericAPIView两个重要的类属性:
queryset:序列化或反序列化指定的queryset,需要指定
serializer_class:序列化类需要指定
lookup_field:查询单条的路由通过转换器分出来的字段名
filter_backends:过滤器的配置
pagination_class:分页器的配置 2.方法:
get_queryset:获取序列化的对象
get_object:获取单个对象,查找时不需要在括号内上传参数pk
get_seriializer:获取序列化类(和它差不多的:get_serializer_class:一般重写它,不调用它)
filter_queryset:过滤器有关 3.代码:
models.py:(和之前没变)
from django.db import models class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32) publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') @property
def publish_detail(self):
return {'name':self.publish.name,'addr':self.publish.addr} @property
def author_list(self):
l = []
for author_obj in self.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32) class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11) serializer.py:(和之前没变)
from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','price','publish','authors','publish_detail','author_list']
extra_kwargs = {
'name':{'max_length':8},
'publish_detail':{'read_only':True},
'author_list':{'read_only':True},
'publish':{'write_only':True},
'authors':{'write_only':True}
} def validate_name(self,name):
if name.startswith('s'):
raise ValidationError('书名不能以s开头')
else:
return name views.py:
rom rest_framework.response import Response
from app01.models import Book
from .serializer import BookSerializer
from rest_framework.generics import GenericAPIView class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self, request):
# 在这里不能直接self.queryset,而是要用drf提供的get_queryset()方法,objs拿到的还是类中的queryset
objs = self.get_queryset()
# 序列化类也要用指定的方法
ser = self.get_serializer(instance=objs, many=True)
return Response(ser.data) def post(self, request):
ser = self.get_queryset(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功','result':ser.data})
else:
return Response({'code':101,'msg':ser.errors})
from rest_framework.mixins import ListModelMixin class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self,request,pk):
obj = self.get_object()
ser = self.get_serializer(instance=obj)
return Response(ser.data) def put(self,request,pk):
obj = self.get_object()
ser = self.get_serializer(instance=obj,data=request.data )
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'修改成功','result':ser.data})
else:
return Response({'code':101,'msg':ser.errors}) def delete(self,request,pk):
self.get_object().delete()
return Response({'code':100,'msg':'删除成功'})
"""
到这一步我们再写其他的表,只需要改变类中:
queryset = Book.objects.all()
serializer_class = BookSerializer
即可
"""

8.基于GenericAPIView+5个视图扩展类

针对接口中5个不同的功能,drf提供了5个不同的类:CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin。这些类封装了5个功能中重复的代码。
urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('books/',views.BookView.as_view()),
path('books/<int:pk>/',views.BookDetailView.as_view())
] views.py: from app01.models import Book
from .serializer import BookSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin class BookView(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self,request):
return self.list(request) def post(self,request):
return self.create(request) class BookDetailView(GenericAPIView,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer def get(self,request,*args,**kwargs):
return self.retrieve(request,*args,**kwargs) def put(self,request,*args,**kwargs):
return self.update(request,*args,**kwargs) def delete(self,request,*args,**kwargs):
return self.destroy(request,*args,**kwargs) serializer.py:
from rest_framework import serializers
from app01.models import Book
from rest_framework.exceptions import ValidationError class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','price','publish','authors','publish_detail','author_list']
extra_kwargs = {
'name':{'max_length':8},
'publish_detail':{'read_only':True},
'author_list':{'read_only':True},
'publish':{'write_only':True},
'authors':{'write_only':True}
} def validate_name(self,name):
if name.startswith('s'):
raise ValidationError('书名不能以s开头')
else:
return name

drf-drf请求、响应、基于GenericAPIView+5个视图扩展类的更多相关文章

  1. DRF的请求响应组件

    目录 DRF的请求响应组件 请求模块(request) 概念 request源码简单分析 响应模块(response) 概念 使用方法 response源码简单分析: 解析模块(parse) 概念 使 ...

  2. DRF框架(五)——context传参,二次封装Response类,两个视图基类(APIView/GenericAPIView),视图扩展类(mixins),子类视图(工具视图),视图集(viewsets),工具视图集

    复习 1.整体修改与局部修改 # 序列化get (给前端传递参数) #查询 ser_obj = ModelSerializer(model_obj) #只传递一个参数,默认是instance的参数,查 ...

  3. DRF (Django REST framework) 中的视图扩展类

    2. 五个扩展类 1)ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码. 该Mixin的list方法 ...

  4. GenericAPIView的使用及和视图扩展类的结合使用

    GenericAPIView的使用 from rest_framework.generics import GenericAPIView GenericAPIView继承 APIView,主要增加了操 ...

  5. DRF中的APIView、GenericAPIView、ViewSet

    1.APIView(rest_framework.views import APIView),是REST framework提供的所有视图的基类,继承自Django的View. 传入到视图方法中的是R ...

  6. DRF视图-5个扩展类以及GenericAPIView基类

    视图 5个视图扩展类 视图拓展类的作用: 提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量. 这 ...

  7. day73:drf:drf视图相关类&路由Routers&创建虚拟环境

    目录 1.APIView 2.GenericAPIView:通用视图类 3.5个视图扩展类:ListModelMixin,CreateModelMixin,RetrieveModelMixin,Upd ...

  8. day74:drf:drf其他功能:认证/权限/限流/过滤/排序/分页/异常处理&自动生成接口文档

    目录 1.django-admin 2.认证:Authentication 3.权限:Permissions 4.限流:Throttling 5.过滤:Filtering 6.排序:OrderingF ...

  9. DRF中五大扩展类及视图集的介绍

    五个扩展类 (1)ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码. 该Mixin的list方法会对 ...

  10. 第二章、drf框架 - 请求模块 | 渲染模块 解析模块 | 异常模块 | 响应模块 (详细版)

    目录 drf框架 - 请求模块 | 渲染模块 解析模块 | 异常模块 | 响应模块 Postman接口工具 drf框架 注册rest_framework drf框架风格 drf请求生命周期 请求模块 ...

随机推荐

  1. OS-HACKNOS-2.1靶机之解析

    靶机名称 HACKNOS: OS-HACKNOS 靶机下载地址 https://download.vulnhub.com/hacknos/Os-hackNos-1.ova 实验环境 : kali 2. ...

  2. AR空间音频能力,打造沉浸式声音体验

    随着元宇宙的兴起,3D虚拟现实广泛引用,让数字化信息和现实世界融合,目前大家的目光主要聚焦于视觉交互层面,为了在虚拟环境中更好的再现真实世界的三维空间体验,引入听觉层面必不可少,空间音频孕育而生. 空 ...

  3. C温故补缺(十五):栈帧

    栈帧 概念 栈帧:也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构,每次函数的调用,都会在调用栈(call stack)上维护一个独立的栈帧(stack frame) 栈帧的内容 函数的 ...

  4. C温故补缺(十一):文件读写

    文件读写 打开文件 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件 FILE *fopen( const char *filename, const char *mode ); fil ...

  5. MyBatis-Plus 分页插件过时

    引用:https://blog.csdn.net/zyw562123314/article/details/108903456//分页插件老版本过时 旧版本配置 @Bean public Pagina ...

  6. 深度学习GPU加速配置方法

    深度学习GPU加速配置方法 一.英伟达官方驱动及工具安装 首先检查自己的电脑驱动版本,未更新至最新建议先将驱动更新至最新,然后点击Nvidia控制面板 2.在如下界面中点击系统信息,点击显示可以看见当 ...

  7. MYSQL下载 环境配置 修改密码 基本SQL语句

    目录 存取数据的演变史 数据库软件应用史 数据库的本质 数据库的分类 关系型数据库 特征 常见关系型数据库 非关系型数据库 特征 常见非关系型数据库 mysql简介 mysql下载 启动mysql 系 ...

  8. Blazor组件自做十三: 使用 Video.js 在 Blazor 中播放视频

    Video.js 是一个具有大量功能的流行的视频和音频 JavaScript 库,今天我们试试集成到 Blazor . Blazor VideoPlayer 视频播放器 组件 示例 https://b ...

  9. Go语言性能剖析利器--pprof实战

    作者:耿宗杰 前言 关于pprof的文章在网上已是汗牛充栋,却是千篇一律的命令介绍,鲜有真正实操的,本文将参考Go社区资料,结合自己的经验,实战Go程序的性能分析与优化过程. 优化思路 首先说一下性能 ...

  10. 【机器学习】李宏毅——AE自编码器(Auto-encoder)

    1.What 在自编码器中,有两个神经网络,分别为Encoder和Decoder,其任务分别是: Encoder:将读入的原始数据(图像.文字等)转换为一个向量 Decoder:将上述的向量还原成原始 ...