DRF从入门到精通六(排序组件、过滤组件、分页组件、异常处理)

文章目录

  • 一、排序组件
    • 继承GenericAPIView使用DRF内置排序组件
    • 继承APIView编写排序
  • 二、过滤组件
    • 继承GenericAPIView使用DRF内置过滤器实现过滤
    • 使用第三方模块django-filter实现and关系的过滤
    • 自定制过滤类
    • 排序搭配过滤使用
  • 三、分页组件
    • 分页器一:Pagination(基本分页)
    • 分页器二:LimitOffsetPagination(偏移分页)
    • 分页器三:CursorPagination(游标分页)
  • 四、异常处理

一、排序组件

一般涉及到了查询所有才有排序,对于表模型查询所有数据时需要根据某个字段进行排序时,我们就可以使用到REST framework提供的内置排序组件OrderingFilter来帮助我们快速指名数据按照指定字段进行排序

使用方法

  1. 导入DRF内置排序组件:from rest_framework.filters import OrderingFilter
  2. 在视图类中设置类属性:filter_backends=[OrderingFilter]
    注意这里能使用这个类属性,只有是继承了GenericAPIView才行。否则无法使用
    所以像继承APIView则无法使用内置过滤器
  3. REST framework会在请求的查询字符串参数中检查是否包含了ordering参数
  4. 如果包含了ordering参数,则按照ordering参数指明排序字段对数据集进行排序
  5. 前端可以传递的ordering参数的可选字段值需要再ordering_fields中指明

继承GenericAPIView使用DRF内置排序组件

	'需要有表数据,我这里直接沿用上一篇博客中的使用,然后使用自动生成路由的方式'from rest_framework.generics import ListAPIViewfrom rest_framework.viewsets import ViewSetMixinfrom rest_framework.filters import OrderingFilterfrom .serializer import BookSerializerfrom . import modelsclass BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializer'配置属性'filter_backends = [OrderingFilter]'必须指定表模型数据字段'ordering_fields = ['price'] # 可以写多个排序字段# ordering_fields = ['price','id']'127.0.0.1:8000/api/v2/books/?ordering=-price 倒序''127.0.0.1:8000/api/v2/books/?ordering=price 升序'

在这里插入图片描述


继承APIView的是使用不了以上DRF提供的排序组件,需要自己写,自己从请求地址中取出排序规则,然后自己排序

继承APIView编写排序

	from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework.viewsets import ViewSetMixinfrom rest_framework.mixins import ListModelMixin'这里我还是沿用上面自动生成路由的方式,所以需要配置ViewSetMixin'class BookView(ViewSetMixin, APIView, ListModelMixin):'由于是APIView需要自己重写list方法,在自动生成路由中是get:list'def list(self, request, *args, **kwargs):'从地址栏中取出过滤条件'print(request.query_params)  # ?ordering=-price,idquery_params = request.query_params  # {ordering:price}'''支持多个条件排序ordering=-price,id'''# try:'127.0.0.1:8000/api/v2/books/?ordering=-price,id'if ',' in query_params.get('ordering'):query = query_params.get('ordering').split(',')book_list = models.Book.objects.all().order_by(*query)else:book_list = models.Book.objects.all().order_by(query_params.get('ordering'))ser = BookSerializer(instance=book_list, many=True)return Response(ser.data)

在这里插入图片描述


二、过滤组件

restful规范中,要求请求地址中带过滤条件,五个接口中,只有查询所有接口需要过滤和排序。

其实上面排序使用的就是DRF内置过滤器,因为排序本就是过滤的一种特殊情况,所以这里就不在过多介绍了

继承GenericAPIView使用DRF内置过滤器实现过滤

	from rest_framework.filters import SearchFilterfrom rest_framework.viewsets import ViewSetMixinfrom rest_framework.generics import ListAPIViewfrom rest_framework.filters import OrderingFilter,SearchFilterclass BookView(ViewSetMixin, GenericAPIView, ListModelMixin):queryset = models.Book.objects.all()serializer_class = BookSerializer'SearchFilter,使用的是模糊匹配'filter_backends = [SearchFilter]'''只能填写表中字段'''search_fields = ['name']search_fields = ['name','price']  可多字段过滤# 127.0.0.1:8000/api/v2/books/?search=东# 127.0.0.1:8000/api/v2/books/?search=46  '因为是多字段过滤,并且SearchFilter是模糊匹配,所以如果多字段中有一样的东西,如1都会被查到'

使用DRF内置过滤器,它搜索结果的关系为or(或)的关系,不是and关系。并且只能是使用关键字search才能使用,如果我们想要用name=东&price=66这种方式的得使用别的方法来实现

在这里插入图片描述


使用第三方模块django-filter实现and关系的过滤

	'首先需要安装第三方模块:pip install django-filter'from django_filters.rest_framework import DjangoFilterBackendfrom rest_framework.viewsets import ViewSetMixinfrom rest_framework.generics import ListAPIView'使用这个第三方模块可以实现and关系,并且只能是精准匹配。并且暂不支持or关系'class BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializerfilter_backends = [DjangoFilterBackend]filterset_fields = ['name', 'price']# 127.0.0.1:8000/api/v2/books/?name=东游记&price=46 精准匹配'但是对于django-filter来讲它是支持扩写的,所以是可以支持模糊匹配,具体操作自寻查找'

在这里插入图片描述

使用这个django-filter还是有局限性的,无法实现or关键以及模糊匹配,那么我们可以使用自定制过滤类


自定制过滤类

	使用步骤:1.定义一个过滤类,并且继承BaseFilterBackend2.重写filter_queryset方法,并且在内部完成过滤规则3.在视图类中配置自定义的过滤类from rest_framework.filters import BaseFilterBackendclass CommonFilter(BaseFilterBackend):def filter_queryset(self, request, queryset, view):'''queryset是之前所有数据,models.Book.object.all()'''# request是当次请求# query_params = request.query_params'方式一:'name = request.query_params.get('name',None)price = request.query_params.get('price',None)res = queryset.filter(name__contains=name,price=price)'方式二:'if request.query_params.get('name'):queryset = queryset.filter(name__contains=request.query_params.get('name'))if request.query_params.get('price'):'支持链式调用'queryset = queryset.filter(price=request.query_params.get('price'))return queryset  # 这里返回过滤后的对象 resfrom .filters import CommonFilter  class BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializer'无需再配置字段了,因为在自定制类中已经写好了过滤规则,所以在视图类中无需配置'filter_backends = [CommonFilter]# 127.0.0.1:8000/api/v2/books/?name=游记&price=666'这样就实现了模糊匹配name字段并且精准匹配price字段,以及查询单个字段的规则'

在这里插入图片描述


排序搭配过滤使用

	from .filters import CommonFilter  # 使用的是上面的自定制过滤类from rest_framework.filters import OrderingFilterclass BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializerfilter_backends = [OrderingFilter,CommonFilter]  # 排序加过滤,从左到右依次执行ordering_fields = ['price','id']

在这里插入图片描述


三、分页组件

分页只针对查询所有的接口,其他四个接口不需要分页。drf内置了三个分页器,对应三种分页方式,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用。一个接口只能有一种分页方式,不能混合分页方式

分页器一:Pagination(基本分页)

通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。

	from rest_framework.pagination import PageNumberPaginationclass CommonPageNumberPagination(PageNumberPagination):page_size = 3 # 默认每页显示的条数page_query_param = 'page' # 使用该关键字指定页码(客户端使用)page_size_query_param = 'size' # 通过该关键字可以手动指定页面显示的数据条数(客户端使用)max_page_size = 5 # 只针对客户端手动指定页面显示的数据条数做出一个限制,但不影响page_size属性。

视图类

	'导入配置的分页类'from .pagination import CommonPageNumberPaginationfrom rest_framework.viewsets import ViewSetMixinfrom rest_framework.generics import ListAPIViewfrom . import modelsfrom .serializer import BookSerializerfrom .filters import CommonFilterfrom rest_framework.filters import OrderingFilterclass BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializer'注意分页方式一个接口只能使用一种,所以没有加中括号'pagination_class = CommonPageNumberPagination'''使用分页并不影响排序和过滤'''filter_backends = [OrderingFilter,CommonFilter]filterset_fields = ['name', 'price']# 127.0.0.1:8000/api/v2/books/?page=2# 127.0.0.1:8000/api/v2/books/# 127.0.0.1:8000/api/v2/books/?page=2&size=3

在这里插入图片描述

响应时额外携带了3个参数,分别是:

  1. count:book接口的数据总量
  2. next:下一页的URL
  3. previous:上一页的URL,如果没有上一页返回None

当然,我们也可以手动指定页面显示的条数,根据page_size_query_param属性值来作为关键字。

在这里插入图片描述

可以看到我们需要显示的是6条数据,而后端只响应了5条,这是因为max_page_size属性值的作用:限制了客户端手动获取数据时最大返回的数据条数。


分页器二:LimitOffsetPagination(偏移分页)

偏移分页,该分页组件作用是:从哪一条数据之后开始显示,以及制定数据显示的条数

前端访问形式:http://127.0.0.1:8080/book/?offset=2&limit=4,这表示从第3条数据之后显示4条数据

自定义分页类

	from rest_framework.pagination import LimitOffsetPaginationclass CommonLimitOffsetPagination(LimitOffsetPagination):# 等同于上面的:page_sizedefault_limit = 2  # 如果前端没有手动指定获取的数据条数时,使用该属性值limit_query_param = 'limit'  # 前端通过该关键字指定数据条数'每页显示条数,查询的条数  例子 ?limit=100 意思就是每页显示100条,如果不传应用default_limit的参数'offset_query_param = 'offset'  # 通过该关键字指定从哪条数据之后开始获取数据'偏移量  举个例子offset=6&limit=30  意思就是从第6条开始,拿30条'# 等同于上面的:max_page_sizemax_limit = 5  # 只限制limit_query_param能够获取的最大数据条数,而不影响default_limit

视图类

	'导入配置的分页类'from .pagination import CommonPageNumberPaginationclass BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializer'注意分页方式一个接口只能使用一种,所以没有加中括号'pagination_class = CommonPageNumberPagination# http://127.0.0.1:8000/api/v2/books/?limit=6&offset=2  从第2条开始拿6条

在这里插入图片描述

从第二条数据之后开始指定获取数据的条数,使用了limit指定了获取6条,但是被max_limit=5给限制了,所以后端只能返回2条数据,如果不使用limit指定获取的数据条数,那么默认使用default_limit=2后端会返回2条数据。


分页器三:CursorPagination(游标分页)

自定义分页类

	from rest_framework.pagination import CursorPaginationclass CommonCursorPagination(CursorPagination):cursor_query_param = 'cursor'  # 按游标查询的查询条件,value值前端是不知道的,只能通过后台返回page_size = 2  # 每页显示多少条啊ordering = 'id'  # 排序规则,必须是表中的字段

视图类

	from .pagination import CommonCursorPaginationclass BookView(ViewSetMixin,ListAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializer'注意分页方式一个接口只能使用一种,所以没有加中括号''另外使用游标分页的方式后就不能再其中使用排序了,因为其内部已经排好序了'pagination_class = CommonCursorPagination'并且只能选择上一页和下一页,不能指定跳转某一页,但是速度快,针对与特别大的数据量,游标分页有优势'

在这里插入图片描述


四、异常处理

REST framework提供了异常处理,我们可以自定义异常处理函数。主要是为了DRF在运行过程中发生的错误进行一个捕获,然后响应友好的提示信息给前端。

自定义异常处理函数:(定制一个异常处理统一的返回格式)

	from rest_framework.views import exception_handler,Response# drf的异常处理是exception_handler处理了,到那时没处理非drf的异常# 自己写个函数,处理drf异常和自己的异常,以后只要是出了异常都会走这里def Common_exception_handler(exc, context):# exc:异常信息# context:执行请求的视图、args、kwargs参数、request请求res = exception_handler(exc, context)# 在此处补充自定义的异常处理if res:  # 有值说明是drf的异常,如果没有值说明是自己的异常# data = {'detail': exc.detail}detail = res.data.get('detail') or "drf异常,请联系系统管理员"return Response({'code':666,'message':detail})else:return Response({'code':777,'message':f"系统异常,请联系管理{str(exc)}"})

在配置文件中声明自定义的异常处理

	REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'appo1.exception.Common_exception_handler',}

如果未声明,会采用默认的方式,如下:

	REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'}

视图类

	'''全局异常处理'''from rest_framework.exceptions import AuthenticationFailed,APIException'''Drf中无论在三大认证还是视图类中 方法执行报错包括主动抛异常都会执行一个函数excption_exception处理异常的函数只要出了异常APIView的dispatch中就可以捕获到 执行配置文件中的'EXCEPTION_HANDLER':'rest_framework.views.exception_handler''''class UserView(ViewSetMixin, APIView):def create(self, request):raise Exception('你出错了')# drf默认能处理自己的异常,它的异常都是继承自APIException的异常# raise AuthenticationFailed('认证失败')return Response({'code':100,'msg':'1111'})

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/305414.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何购买腾讯云的服务器(详解腾讯云服务器购买流程)

腾讯云服务器购买流程直接在官方秒杀活动上购买比较划算,在云服务器CVM或轻量应用服务器页面自定义购买价格比较贵,但是自定义购买云服务器CPU内存带宽配置选择范围广,活动上购买只能选择固定的活动机,选择范围窄,但是…

12.27_黑马数据结构与算法笔记Java(补1)

目录 266 活动选择问题 分析 267 活动选择问题 贪心 268 分数背包问题 贪心 269 0-1 背包问题 贪心 270 斐波那契 动态规划 271 斐波那契 动态规划 降维 272 Bellman Ford 动态规划 分析 273 Bellman Ford 动态规划 实现1 274 Bellman Ford 动态规划 实现2 275 Leetco…

conda环境下Could not build wheels for dlib解决方法

1 问题描述 在安装模型运行的conda环境时,出现如下问题: Building wheels for collected packages: basicsr, face-alignment, dlib, ffmpy, filterpy, futureBuilding wheel for basicsr (setup.py) ... doneCreated wheel for basicsr: filenamebasi…

快速上手makefile自动化构建工具

makefile自动化构建工具 文章目录 makefile自动化构建工具 makefile背景 简单认识makefile 依赖关系与依赖方法 生成项目 清理项目 ACM时间 语法补充 .PHONY修饰 特殊符号替换 Makefile的推导过程 总结 前言: 在windows下,很多东西都是编译器直接帮你做…

电子握力器改造

toy_hand_game 介绍 消耗体力玩具,使用握力器(Grip Strengthener)控制舵机旋转。 开始设想是控制丝杆电机滑动,两套设备就可以控制两个丝杆电机进行“模拟拔河”,后续发现硬件设计错误,ULN2003不能控制两相四线电机,…

c语言:求最小公倍数|练习题

一、题目 输入两个数,求两数的最小公倍数。 如图: 二、思路分析 1、先知道两个数里的最小值(比如:9和6,取6) 2、用2到6,5个数,同时除以9和6,得最小公约数:3 3、用9除33,6除32。得最小…

Python漂浮爱心完整代码

文章目录 环境需求完整代码详细分析环境需求 python3.11.4PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这个库哦~)【注】 python环境搭建请见:https://want595.blog.csdn.net/arti…

k8s-cni网络 10

Flannel vxlan模式跨主机通信原理 在同一个节点上的pod 流量通过cni网桥可以直接进行转发; 在需要跨主机访问时,数据包通过flannel(隧道) 知道另一边的mac地址,就可以拿到另一边的ip地址,然后构建常规的以太网数据包,…

ClickHouse基础知识(二):ClickHouse 安装教程

1. 准备工作 1.1 确定防火墙处于关闭状态 1.2 CentOS 取消打开文件数限制 (1)在 hadoop101 的 /etc/security/limits.conf 文件的末尾加入以下内容 sudo vim /etc/security/limits.conf(2)在 hadoop101 的/etc/security/limits.…

为什么IDEA建议去掉StringBuilder,而要使用“+”拼接字符串

在字符串拼接时应该都见过下面这种提示: 大家普遍认知中,字符串拼接要用StringBuilder,那为什么idea会建议你是用呢,那到底StringBuilder和有什么具体区别呢,我们一起来探究一下。 普通拼接 普通的几个字符串拼接成一…

【头歌实训】kafka-入门篇

文章目录 第1关:kafka - 初体验任务描述相关知识Kafka 简述Kafka 应用场景Kafka 架构组件kafka 常用命令 编程要求测试说明答案代码 第2关:生产者 (Producer ) - 简单模式任务描述相关知识Producer 简单模式Producer 的开发步骤Ka…

主资源公平调度策略

0. 前言 最大最小分配算法:这个比较好理解,就是最大化目前分配到最小资源量的用户或者任务的资源量。举个例子ABC三个任务需要的资源分别为2,5,8个单位,现在有12个单位的资源,一开始时候每个任务平均分配4个单位,这个时候A任务多出2个单位,然后再将这2个单位平均分配为B…