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.mzph.cn/news/582513.shtml

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

相关文章

【JavaScript】闭包机制

✨ 专栏介绍 在现代Web开发中,JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性,还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言,JavaScript具有广泛的应用场景&#x…

java设计模式学习之【解释器模式】

文章目录 引言解释器模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用表达式解析示例代码地址 引言 在我们的日常生活中,语言的翻译和理解是沟通的关键。每种语言都有自己的语法规则,而翻译人员和计算机程序需要理解并遵循这些规则来…

手写Promise

目录 前言 状态 使用方法 构造函数 对象 结论 第一阶段 搭建基本结构 思路 代码实现 测试一下 实现then方法获取异步值 思路 改造代码如下 测试一下 成功场景 失败场景 实现类的resolve,reject以及catch方法 思路 代码实现 测试一下 第一阶段总结 第二阶…

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(11)

接前一篇文章:《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(10) 1.3 PCI总线的存储器读写总线事务 1.3.2 Posted和Non-Posted传送方式 PCI总线规定了两类数据传送方式,分别是Posted和Non-Posted数据传送…

关于Redis面试题

前言 之前为了准备面试,收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文:https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv Redis 是什么 全名:远程字典服务。这是一个开源的在内存中的数据结构存…

硅像素传感器文献调研(二)

写在前面:从上篇文章的参考文献中看到一篇文献,现在也精读一下,今天还有一个任务是把上篇文献整体脉络用流程图的形式完整梳理一下。 哈哈哈哈哈哈:代表没太搞明白的部分 如何写论文: 引言部分:基础理论…

Python入门知识点分享——(十一)if条件语句

if条件语句是一种编程语言中用于控制程序流程的结构。它根据一个条件的真假来决定执行不同的代码块。 if条件语句通常由if关键字、一个条件表达式和一个代码块组成。条件表达式可以是一个返回布尔值的表达式,如果条件为真,则执行代码块中的代码&#xf…

01_软件测试

01_软件测试 学习目标 1、能复述软件测试的定义 2、能说出7种测试分类的区别 3、能说出质量模型的重点5项 4、能说出测试流程的6个步骤 5、能说出测试模板8个要素 认识软件及测试 什么是软件 软件:控制计算机硬件工作的工具 软件的基本组成 软件生产过程 什么是软…

vue多条数据渲染(带图片)

我在这用的为接口数据&#xff1a; 先调用接口获取需要的数据: 然后用&#xff1a;data绑定需要渲染的数据&#xff1b;&#xff08;记得包裹在<el-table>标签中&#xff09; 然后以此循环渲染数据&#xff1b;那怎么渲染出来图片呢&#xff1f; 在<el-table-column…

Vue3-25-路由-路由的基本使用

对路由的理解 路由 &#xff1a; 就是前端对页面路径的拦截&#xff0c;根据不同的路径渲染不同的组件&#xff0c; 从而实现单页应用中的页面局部刷新的功能。安装路由依赖 根据使用的不同的包管理工具采用不同的命令&#xff0c; 常见的三种包管理工具和对应的命令如下&…

day44 1228

作业1&#xff1a; #include <iostream>using namespace std;class Person {int *age;string &name; public:Person(int age,string &name):age(new int(age)),name(name){cout << "Person的构造函数" <<endl;}~Person(){delete age;cout…

【Java系列】多线程案例学习——基于阻塞队列实现生产者消费者模型

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习JavaEE的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录…

如何在Mac中设置三指拖移,这里有详细步骤

三指拖移手势允许你选择文本&#xff0c;或通过在触控板上用三指拖动窗口或任何其他元素来移动它。它可以用于快速移动或调整窗口、文件或图像在屏幕上的位置。 然而&#xff0c;这个手势在默认情况下是禁用的&#xff0c;因此在本教程中&#xff0c;我们将向你展示如何在你的…

数据库系统原理例题之——SQL 与关系数据库基本操作

SQL 与关系数据库基本操作 第四章 SQL 与关系数据库基本操作【例题】一 、单选题二 、填空题三 、简答题四 、设计题 【答案&解析】一、单选题二、填空题三、简答题四、设计题 【延伸知识点】【延伸知识点答案&解析】 第四章 SQL 与关系数据库基本操作 【例题】 一 、…

springboot整合minio做文件存储

一,minio介绍 MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等&#xff0c;而一个对象文件可以是任意大小&…

verilog rs232串口模块

前面发了个发送模块&#xff0c;这次补齐&#xff0c;完整。 串口计数器&#xff0c;波特率适配 uart_clk.v module uart_clk(input wire clk,input wire rst_n,input wire tx_clk_en,input wire rx_clk_en,input wire[1:0] baud_sel,output wire tx_clk,output wire rx_clk )…

Kubernetes快速实战与核心原理剖析

K8S 概览 K8S 是什么 K8S 官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ K8S 是 Kubernetes 的全称&#xff0c;源于希腊语&#xff0c;意为“舵手”或“飞行员”。Kubernetes 是用于自动部署、扩缩和管理容器化应用程序的开源系统。 Kubernetes 源自 Google 15 年…

EDKII:第一个Helloworld

目录 0 说明 1 步骤 1.1 简介 1.2 创建新文件 1.3 创建printhelloworld.c、printhelloworld.inf&#xff1a; 1.4 修改MdeModulePkg\MdeModulePkg.dsc 1.5 修改EmulatorPkg\EmulatorPkg.dsc 1.6 运行 0 说明 上篇文章记录了如何安装UEFI环境&#xff0c;在这里将会写下…

c++ / day03

1. 定义一个Person类&#xff0c;包含私有成员&#xff0c;int *age&#xff0c;string &name&#xff0c;一个Stu类&#xff0c;包含私有成员double *score&#xff0c;Person p1&#xff0c;写出Person类和Stu类的特殊成员函数&#xff0c;并写一个Stu的show函数&#xf…

CodeWhisperer——轻松使用一个超级强大的工具

CodeWhisperer 简介 CodeWhisperer是亚⻢逊云科技出品的一款基于机器学习的通用代码生成器&#xff0c;可实时提供代码建议。 CodeWhisperer有以下几个主要用途&#xff1a; 解决编程问题&#xff0c;提供代码建议&#xff0c;学习编程知识等等&#xff0c;并且CodeWhisper…