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_lengthmin_length:设置反序列化时的最大长度和最小长度

  max_valuemin_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,自定义权限控制类

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
View Code

 

限流:限制用户访问接口的频率

  1,分别限流

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        # 针对未登录(匿名)用户的限流控制类
        'rest_framework.throttling.AnonRateThrottle',
        # 针对登录(认证)用户的限流控制类
        'rest_framework.throttling.UserRateThrottle'
    ),
    # 指定限流频次
    'DEFAULT_THROTTLE_RATES': {
        # 认证用户的限流频次
        'user': '5/minute',
        # 匿名用户的限流频次
        'anon': '3/minute',
    },
}
View Code

统一限流:

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)

  

分页:

  设置全局分页类

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 5  # 页容量
}
View Code

注意:设置全局分页类之后,默认情况下凡是使用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框架都可以自动处理

自定义异常处理函数:

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'
}
原文地址:https://www.cnblogs.com/wjun0/p/11723635.html