drf-drf请求、响应、基于GenericAPIView+5个视图扩展类
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个视图扩展类的更多相关文章
- DRF的请求响应组件
目录 DRF的请求响应组件 请求模块(request) 概念 request源码简单分析 响应模块(response) 概念 使用方法 response源码简单分析: 解析模块(parse) 概念 使 ...
- DRF框架(五)——context传参,二次封装Response类,两个视图基类(APIView/GenericAPIView),视图扩展类(mixins),子类视图(工具视图),视图集(viewsets),工具视图集
复习 1.整体修改与局部修改 # 序列化get (给前端传递参数) #查询 ser_obj = ModelSerializer(model_obj) #只传递一个参数,默认是instance的参数,查 ...
- DRF (Django REST framework) 中的视图扩展类
2. 五个扩展类 1)ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码. 该Mixin的list方法 ...
- GenericAPIView的使用及和视图扩展类的结合使用
GenericAPIView的使用 from rest_framework.generics import GenericAPIView GenericAPIView继承 APIView,主要增加了操 ...
- DRF中的APIView、GenericAPIView、ViewSet
1.APIView(rest_framework.views import APIView),是REST framework提供的所有视图的基类,继承自Django的View. 传入到视图方法中的是R ...
- DRF视图-5个扩展类以及GenericAPIView基类
视图 5个视图扩展类 视图拓展类的作用: 提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量. 这 ...
- day73:drf:drf视图相关类&路由Routers&创建虚拟环境
目录 1.APIView 2.GenericAPIView:通用视图类 3.5个视图扩展类:ListModelMixin,CreateModelMixin,RetrieveModelMixin,Upd ...
- day74:drf:drf其他功能:认证/权限/限流/过滤/排序/分页/异常处理&自动生成接口文档
目录 1.django-admin 2.认证:Authentication 3.权限:Permissions 4.限流:Throttling 5.过滤:Filtering 6.排序:OrderingF ...
- DRF中五大扩展类及视图集的介绍
五个扩展类 (1)ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码. 该Mixin的list方法会对 ...
- 第二章、drf框架 - 请求模块 | 渲染模块 解析模块 | 异常模块 | 响应模块 (详细版)
目录 drf框架 - 请求模块 | 渲染模块 解析模块 | 异常模块 | 响应模块 Postman接口工具 drf框架 注册rest_framework drf框架风格 drf请求生命周期 请求模块 ...
随机推荐
- MySQL数据库的性能分析 ---图书《软件性能测试分析与调优实践之路》-手稿节选
1 .MySQL数据库的性能监控 1.1.如何查看MySQL数据库的连接数 连接数是指用户已经创建多少个连接,也就是MySQL中通过执行 SHOW PROCESSLIST命令输出结果中运行着的线程 ...
- C#怎么在生成解决方案的过程中执行perl脚本(C#早期绑定)
转载 怎么在生成解决方案的过程中执行perl脚本 早期绑定在编译期间识别并检查方法.属性.函数,并在应用程序执行之前执行其他优化.在这个绑定中,编译器已经知道它是什么类型的对象以及它拥有的方法或属性. ...
- Java:String、StringBuilder、StringJoiner学习笔记
String创建的俩种方式 1.直接赋值 String str = "Hello World!"; 当使用直接赋值的方式去创建字符串的时候,虚拟机会去串池里去检查字符串是否存在,如 ...
- Go语言核心36讲03
[Go语言代码较多,建议配合文章收听音频.] 你好,我是郝林.从今天开始,我将和你一起梳理Go语言的整个知识体系. 在过去的几年里,我与广大爱好者一起见证了Go语言的崛起. 从Go 1.5版本的自举( ...
- 【ASP.NET Core】MVC控制器的各种自定义:修改参数的名称
在上一篇中,老周演示了通过实现约定接口的方式自定义控制器的名称. 至于说自定义操作方法的名称,就很简单了,因为有内置的特性类可以用.看看下面的例子. [Route("[controller] ...
- DP?
杨斌涵//aad69d38 分治优化DP 分治优化1D/1D dp 对于一类 \[f(x) = \min_{k = y}^{x - 1} w(l, r) \] 即所有 \(w(l,r)\) 事先已知, ...
- java.util.Date和java.util.Calendar
Date date = new Date();//分配初始化一个Date()对象 Calendar cal = Calendar.getInstance();//获取一个基于当前时间的日历 int d ...
- SSH(三)创建包和第一个页面
在ssh web项目src下一次创建 com.ssh/ .action .dao .entity .service 四个包,example: 在entity包下创建class,name: produc ...
- redis集群之主从复制集群的原理和部署
最近在复盘redis的知识,所以本文开始希望介绍下redis的集群架构.原理以及部署:本文主要介绍redis的主从复制集群,包括其架构模型,原理,高可用等: 一.主从集群的介绍 redis的主从复 ...
- 利用云服务提供商的免费证书,在服务器上发布https前端应用和WebAPI的应用
我们如果要在服务器上发布https前端应用和WebAPI的应用,那么我们就需要用到https证书了.我们一般发布的应用的云服务器上,都会提供一定量的相关的免费证书(一般为20个)供我们使用,每个一年期 ...