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. javax.script.ScriptException: Cannot find engine named: 'nashorn', ensure you set language field in JSR223 Test Element: JSR223 预处理程序

    jmeter运行脚本报错,跟java版本有关,做个记录. 1. 问题记录: 执行登录接口测试,登录失败.点击jmeter右上角[黄色!],查看错误日志.显示如下: 2022-09-23 10:29:5 ...

  2. java学习之JSON

    0X00前言 JSON可以说是javascript的一种数据类型,我们学习JSON是为了在客户端的数据给读取出来,官方的解释是:概述:JSON(JavaScript Object Notation, ...

  3. C#怎么在生成解决方案的过程中执行perl脚本(C#早期绑定)

    转载 怎么在生成解决方案的过程中执行perl脚本 早期绑定在编译期间识别并检查方法.属性.函数,并在应用程序执行之前执行其他优化.在这个绑定中,编译器已经知道它是什么类型的对象以及它拥有的方法或属性. ...

  4. vulnhub靶场之VIKINGS: 1

    准备: 攻击机:虚拟机kali.本机win10. 靶机:DRIPPING BLUES: 1,网段地址我这里设置的桥接,所以与本机电脑在同一网段,下载地址:https://download.vulnhu ...

  5. Web安全Day1 - SQL注入、漏洞类型

    Web安全Day1 - SQL注入.漏洞类型 1. SQL注入 1.1 漏洞简介 1.2 漏洞原理 1.3 漏洞危害 2. SQL漏洞类型 2.1 区分数字和字符串 2.2 内联SQL注入 2.3 报 ...

  6. 系统内置APK并签名并配置AndroidStudio

    前言 最近在集成内置APK的时候遇到了些问题,遂整理一份文档以记录. 一,APP内置进系统固件 将APK源码或编译出的apk文件放在package或vendor等目录下,并且编写相应的android, ...

  7. 3 c++编程-提高篇-模版

    ​ 重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦!  生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦!  系列文章列表: 1 c+ ...

  8. 本地JS文件批量压缩

    最近在维护一个小后台项目,有段JS需要压缩上传到CDN存储服务器.由于之前压缩的JS文件都比较少,都是手动压缩的.这次需要压缩的文件比较多,所以用了批量压缩.特此记录一下,方便大家和自己以后再用到的时 ...

  9. 【开发必备】单点登录,清除了cookie,页面还保持登录状态?

    背景 本地搭建了一台认证服务器.两台资源服务器,看看请求的过程 开始 没登录,直接请求资源服务器,结果跳转到的登录页面 登录后,请求了认证服务器的登录接口,然后顿重定向,最后回到了资源服务器的接口,页 ...

  10. postgresql函数:定期删除模式下指定天数前的表数据及分区物理表

    一.现有函数-- 1.现有函数调用select ods.deletePartitionIfExists('fact_ship' || '_' || to_char(CURRENT_DATE - INT ...