DRF框架(django rest framework)
1,DRF框架?
Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。通常简称为DRF框架 或 REST framework。
Django REST framework 可以帮助我们大大提高REST API 的开发速度,目的就是简化代码
2,序列化和反序列化
序列化:将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等),例 如 Django中的模型类对象转换为字典或JSON字符串,这个转换过程我们称为序列化。
反序列化:将其他格式(字典、JSON、XML等)转换为程序中的数据,例如将JSON字符串或字典转换保存为Django中的模型类对象,这个过程我们称为反序列化
序列化(侠义):将对象转为字典,json
反序列化(侠义):将字典,json转换为对象
3,Django REST framework 的使用:
1,下载安装:pip install djangorestframework
2,settings中进行注册 INSTALL_APPS ‘rest_framework’
3, DRF 框架序列化:只能将对象转换为字典,不能转换为json
4,DRF框架反序列化:数据校验,数据保存(新增和更新)
4,使用序列化器必须先定义序列化器:
序列化器的定义:
class <序列化器类名> (serializer.Serailizers):
字段 = serializers.字段类型(参数)
5,序列化功能:
1,创建序列化器类对象 serializer = 类名(user) (把对象放入类中)
2,获取序列化后的数据 res = serializers.data() print(res)
6,反序列化功能:
1,创建序列化器对象 serializer = 类名(data={xx}) 把前端传入的字典放入其中
2,进行参数校验 serializer.is_valid 返回true 或 false 代表校验成功和失败
3,获取校验失败的错误信息:serializers.errors 如果成功返回的是空字典
4,获取校验后的数据:serializers.validated_data 返回的是校验成功后的有序字典orderdict
7,序列化器使用的总结:
1,无论是序列化还是反序列化都需要创建序列化器对象
serializers = UserSerializer(instance = none,data={})
序列化时,将序列化对象传给intsance
反序列化时,将字典传给data
8,序列化器类的通用参数:
reade_only (该字段只在序列化时使用设为true)
write_only (该字段只在反序列化时使用设为true)
read_only 和 write_only 不指定时为false ,表示序列化和反序列化时都使用
required 只争对反序列化时使用,默认为true,代表反序列化时必须传入该字段参数,
default 设置序列化或反序列化时的默认值
max_length和min_length:设置反序列化时的最大长度和最小长度
max_value和min_value:设置反序列化时的最大值和最小值
9,序列化操作
1,序列化单个对象
book = BookInfo.objects.get(id=1) serizlizer = BookInfoSerializer(book) res = serializer.data
2,序列化多个对象
books = BookInfo.objects.all() #Queryset serializer = BookInfoSerializer(books,many=True) res = serializer.data
3,关联对象 嵌套序列化
#1,将关联对象序列化为关联对象的主键 hbook = serializer.PrimarykeyRelatedFiled(label = '图书',read_only = true) 或 hbook = serializer.PrimarykeyRelatedFiled(label = '图书',queryset=BookInfo.objects.all()) #2,使用指定的序列化器将关联对象一并序列化 hbook = BookInfoSerializer() #3,将关联对象序列化为关联对象模型类__str__的返回值 hbook = serializer.StringRelatedFiled(lable='图书')
注意:和一个对象关联的对象如果有多个,在进行嵌套序列化字段定义时,需要加 many=true
10 ,反序列化操作 (可以进行校验和保存)校验只能进行数据是否完整,类型是否正确,以及一些选项参数对data中的数据进行校验
1, 补充校验的三种方式:
注意:方式一 :在定义序列化器类外定义一个函数进行校验,在字段后面添加 validators = 函数名 (不常用)
方法二:在定义序列化器类里添加函数,其中函数名必须是 validate_<字段名> (缺点是只能对单个字段进行校验)
方法三 : 在定义序列化器类里添加函数,可以进行多个字段的对比,函数名必须是 validata
2,保存数据:
前提:必须校验通过ser.is_valid()
使用:serializer.save() 内部可能会调用序列化器类的create或update方法,(如果序列化器类继承serializer.Serializer,需要重写这两个方法,该父类为实现,如果继承serializer.ModelSerializer,父类已经实现)
创建序列化器对象时,如果只传入instance,save()方法被调用,否则create()方法被调用(create方法调用时instance和data参数都要传入)
3,ModelSerializer类的使用
使用:序列化器需要对应是Django的模型类
特点:自动生成序列化器类中的字段
默认已经实现create和update方法
11,APIView视图类
APIView是View的子类,
区别:1,请求对象:Request
request.data :包含解析之后的请求体中的数据,相当于之前的request.POST | request.body | request.FILEs
request.query_params : 包含了解析之后的查询字符串中的数据 QueryDict
2,响应对象:response(原始的响应数据)
根据客服端请求头中Accept自动转换为对应的格式,不需要指定,直接返回res.data ,默认返回json
3, 自动处理APIException的子类异常和Http404
4,其他权限,认证,权限,限流 (后面细说)
12,GenericAPIView视图类
class BookListView(GenericAPIView): #指定视图所使用的序列化器类 serializer_class = BookInfoSerializer #名字必须是serializer_class,父类已经定义,但为None,需要自己指定 #指定视图所使用的查询集 queryset = BookInfo.objects.all() #名字也是必须是queryset,和上面一样,可以到源码进行查看
继承genericAPIView后可以调用下面的方法:
get_serializer_class : 获取指定的序列化器类
get_serializer :获取指定的序列化器类对象
get_queryset:获取指定的查寻集
get_object : 从指定查询集查询一个对象进行返回,默认根据url地址提取的pk进行查询,所以不需要传递参数pk,该函数会制动从url中进行匹配
注意:使用get_serializer_class 和get_serializer 之前必须先指定serializer_class
使用get_queryset和get_object必须先指定queryset 属性
2,GenericAPIView 和APIView 的区别:继承自APIView
1) 增加操作序列化器相关属性和方法
2) 增加数据库查询相关属性和方法
3) 过滤,排序,分页 (后面细说)
3,GenericAPIView 案例:(增,删,改,查)
#/books/ class BookListView(GenericApIview): #指定视图使用的序列化器类 serializer_class = BookInfoSerializer() #序列化器类 #指定查询集 queryset = BookInfo.objects.all() #查询所有书籍 def get(self,request): books = self.get_queryset() # Queryset:查询集 #将所有图书数据通过json进行返回 ser = self.get_serializer(books,many=true) #多个加many=true return Response(ser.data) #ser.data 将序列化后的数据进行返回 #新增书籍 def post(self,request): #校验前端传入的数据 ser = self.get_serializer(data=request.data) ser.is_valid(raise_exception=true) #保存数据 ser.save() #调用序列化器类中的create方法 #将新增的图书进行返回 return Response(ser.data,status=status.HTTP_201_CREATE)
class BookDetailView(GenericAPIView): serializer_class = BookInfoSerializer() queryset = BookInfo.objects.all() #查找指定图书 def get(self,request,pk): book = self.get_object() #不用传参数,改函数会自动在url中查找pk的值 ser = self.get_serializer(book) return Response(ser.data) #修改指定图书 def put(self,request,pk): book = self.get_object() #参数校验 ser = self.get_serializer(book,data=request.data) ser.is_valid(raise_exception=true) #校验通过保存数据 ser.save() return Response(res.data) #删除指定图书 def delete(self,request,pk): book = self.get_object() book.delete() return Response(status=status.HTTP_204_NO_CONTENT)
13 , Mixin扩展类
继承object,不能单独使用,需要配合GenericAPIView来进行使用
DRF框架提供5个Mixin扩展类,就是对上面五个函数进行封装:
# 自己封装Mixin扩展类 class MyListModelMixin(object): def list(self, request, *args, **kwargs): """封装获取一组数据的通用代码流程""" query_set = self.get_queryset() # QuerySet:查询集 serializer = self.get_serializer(query_set, many=True) return Response(serializer.data) class MyCreateModelMixin(object): def create(self, request, *args, **kwargs): """封装新增一条数据通用代码流程""" serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() # 调用序列化器类中的create return Response(serializer.data, status=status.HTTP_201_CREATED) # /books/ class BookListView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): # 指定视图使用的序列化器类 serializer_class = BookInfoSerializer # 指定视图使用的查询集 queryset = BookInfo.objects.all() # serializer_class = HeroInfoSerializer # queryset = HeroInfo.objects.all() def get(self, request): return self.list(request) def post(self, request): return self.create(request) class MyRetrieveModelMixin(object): def retrieve(self, request, *args, **kwargs): """封装获取指定数据通用代码流程""" instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data) # obj = MyRetrieveModelMixin() # obj.retrieve() class MyUpdateModelMixin(object): def update(self, request, *args, **kwargs): """封装修改指定数据通用代码流程""" instance = self.get_object() serializer = self.get_serializer(instance, data=request.data) serializer.is_valid(raise_exception=True) serializer.save() # 调用序列化器类中的update return Response(serializer.data) class MyDestroyModelMixin(object): def destroy(self, request, *args, **kwargs): """封装删除指定数据的通用代码流程""" instance = self.get_object() instance.delete() return Response(status=status.HTTP_204_NO_CONTENT)
# 系统封装的 # /books/(?P<pk>\d+)/ # /books/100/ class BookDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView): serializer_class = BookInfoSerializer queryset = BookInfo.objects.all() def get(self, request, pk): return self.retrieve(request, pk) def put(self, request, pk): return self.update(request, pk) def delete(self, request, pk): return self.destroy(request, pk)
14,子类视图:
继承了GenericAPIView和对应的Mixin扩展类,而且还提供了对应的请求处理函数(get,post)
class BookListView(ListAPIView): serializer_class = BookInfoSerializer queryset = BookInfo.objects.all()
15,视图集:
概念:将一组相关的API接口放在同一个类中,这个类就叫视图集。
基本使用:
1,继承父类ViewSet 2, 视图集中处理方法不以请求方发命名(get,..),而是以对应的操作命名:list,create,retrieve,update,destroy 3, 进行url地址配置时,需要指明请求方式,请求url地址时对应的处理方法
视图集父类:
ViewSet(继承ViewSetMixin和APIView)
GenericViewSet(继承ViewSetMixin和GenericAPIView) 可以配合Mixin扩展类来提供对应的处理函数
ModelViewSet(继承GenericviewSet和5个Mixin扩展类) 常用
ReadOnlymodelViewSet(继承GenericViewSet和2个Mixin扩展类) (ListModelMixin和RetievemodelMixin)
视图集添加额外的API方法即可,注意不要和其他API方法名有冲突
* 直接在视图集中添加API方法即可,注意不要和其他API方法名有冲突
* 添加之后需要进行url地址配置
16,路由router
作用:动态生成视图集中API接口的url 配置项
使用:
lookup_value_regex:
设置router生成路由时,从url中提取pk参数对应的正则表达式
视图集中额外API接口配置项生成:
需要添加action装饰器(导入 from rest_framework.decorators import action)
注意:detail = true或false,看是否需要从url中提取PK,需要就设置为true
defaultRouter和SimpleRouter区别:
1,DefaultRouter多生成一个根路径/配置项
2,每个配置项都可以直接根据.json,返回json数据
17 ,认证 | 权限 | 限流
1,认证:
DRF框架默认全局支持两种认证方法:session认证和基本认证
可以修改全局的认证方式:
REST_FRAMEWORK = { # 修改全局认证方式 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', # 仅支持session认证 ), }
# 指定视图自己的认证方式,此处仅支持session认证 authentication_classes = [SessionAuthentication]
权限:
1,DRF框架默认全局权限设置为:AllowAny,代表允许所有人访问
2,可以修改全局的权限控制方式
REST_FRAMEWORK = { # 修改全局权限控制方式 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', # 允许认证用户 ) }
指定视图自己的权限控制方式,此处代表只有认证过的用户才能访问本视图集中的接口
permission_classes = [IsAuthenticated]
3,自定义权限控制类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class MyPermission(BasePermission): def has_permission(self, request, view): """判断用户对使用这个权限控制类的视图中的API接口是否有访问权限""" return True def has_object_permission(self, request, view, obj): """判断用户对使用这个权限控制类中视图中某个对象是否有访问权限""" # get_object: # 需求:id为1或3的对象用户可以访问,其他的对象不允许访问 if obj.id in (1, 3): return True return False
限流:限制用户访问接口的频率
1,分别限流
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( # 针对未登录(匿名)用户的限流控制类 'rest_framework.throttling.AnonRateThrottle', # 针对登录(认证)用户的限流控制类 'rest_framework.throttling.UserRateThrottle' ), # 指定限流频次 'DEFAULT_THROTTLE_RATES': { # 认证用户的限流频次 'user': '5/minute', # 匿名用户的限流频次 'anon': '3/minute', }, }
统一限流:
REST_FRAMEWORK = { # 针对匿名用户和认证用户进行统一的限流控制 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.ScopedRateThrottle', ), # 指定限流频次选择项 'DEFAULT_THROTTLE_RATES': { 'upload': '3/minute', 'contacts': '5/minute' }, }
统一限流,还需要在视图中通过属性throttle_scope指定限流选项
18 ,过滤 | 排序 | 分页
过滤:
1,安装:pip install django-filter
2,注册子应用,添加过滤配置
3,在视图中通过filter_fields属性指定过滤字段
排序:
在视图中排序设置:(前端在查询字符串中指定排序字段,http://xxxx.com/?ordering=id)
分页:
设置全局分页类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 5 # 页容量 }
注意:设置全局分页类之后,默认情况下凡是使用ListModelMixin中的List返回数据的API,都会使用全局分页类进行分页,如果要取消,可以在该视图中设置:
pagination_class = None
自定义分页类;
# ?page=<页码>&pagesize=<页容量> class StandardResultPagination(PageNumberPagination): # 默认分页页容量 page_size = 3 # 指定页容量参数的名称 page_size_query_param = 'pagesize' # 分页最大页容量 max_page_size = 5
注意:自定义分页类可以设置为全局分页类或指定视图自己使用的分页类
19,异常处理
只要继承了APIView或者它的子类,视图中的处理异常:APIException子类异常或HTTP404,DRF框架都可以自动处理
自定义异常处理函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from rest_framework.views import exception_handler as drf_exception_handler from rest_framework.response import Response from rest_framework import status from django.db import DatabaseError def exception_handler(exc, context): # 调用DRF框架默认异常处理函数 response = drf_exception_handler(exc, context) if response is None: # DRF框架不能处理此异常,自己处理:DatabaseError if isinstance(exc, DatabaseError): response = Response({'detail': '数据库错误!!!'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) return response
修改EXCEPTION_HANDLER配置项
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'booktest.utils.exceptions.exception_handler' }