当前位置: 首页 > news >正文

不让Django DRF ListAPIView 类进行2次查询

在 Django REST Framework (DRF) 的 ListAPIView 或类似视图类中,默认情况下确实会执行两次 SQL 查询

  1. 第一次查询:获取符合条件的数据列表(由 get_queryset() 决定)。
  2. 第二次查询:计算总记录数(用于分页,如 count(*))。

如果你 不需要分页,或者 不想额外查询总数,可以采取以下方法优化。


方法 1:禁用分页(完全移除总数查询)

如果不需要分页,直接在视图类中设置 pagination_class = None

from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPaginationclass MyListView(ListAPIView):queryset = MyModel.objects.all()serializer_class = MySerializerpagination_class = None  # 禁用分页,不会查询总数

这样 DRF 只会执行 get_queryset() 的查询,不会额外计算 count(*)


方法 2:使用 LimitOffsetPaginationCursorPagination 并优化

如果仍然需要分页,但想减少查询次数:

(1)使用 LimitOffsetPagination + 缓存总数

from rest_framework.pagination import LimitOffsetPaginationclass OptimizedPagination(LimitOffsetPagination):def paginate_queryset(self, queryset, request, view=None):# 不计算总数(适用于前端无限滚动等场景)self.count = None  # 阻止 count 查询return super().paginate_queryset(queryset, request, view)class MyListView(ListAPIView):queryset = MyModel.objects.all()serializer_class = MySerializerpagination_class = OptimizedPagination  # 不查询总数

这样分页仍然可用,但不会执行 count(*) 查询。

(2)使用 CursorPagination(基于游标的分页,不查询总数)

from rest_framework.pagination import CursorPaginationclass MyCursorPagination(CursorPagination):ordering = "-created_at"  # 必须指定排序字段page_size = 20class MyListView(ListAPIView):queryset = MyModel.objects.all()serializer_class = MySerializerpagination_class = MyCursorPagination  # 游标分页,不查询总数

CursorPagination 适用于 无限滚动 场景,不会计算总数,性能更好。


方法 3:手动覆盖 paginate_queryset 避免 count 查询

如果你想完全控制分页逻辑,可以手动覆盖 paginate_queryset

from rest_framework.generics import ListAPIView
from rest_framework.response import Responseclass MyListView(ListAPIView):queryset = MyModel.objects.all()serializer_class = MySerializerdef paginate_queryset(self, queryset):# 直接返回数据,不计算总数return list(queryset)  # 强制求值,避免惰性查询问题def list(self, request, *args, **kwargs):queryset = self.filter_queryset(self.get_queryset())page = self.paginate_queryset(queryset)if page is not None:serializer = self.get_serializer(page, many=True)return Response(serializer.data)serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)

这样 DRF 不会执行额外的 count(*) 查询。


方法 4:使用 values()iterator() 优化查询

如果数据量很大,可以使用 values()iterator() 减少内存占用:

class MyListView(ListAPIView):def get_queryset(self):return MyModel.objects.values("id", "name")  # 只查询必要字段

或者:

class MyListView(ListAPIView):def get_queryset(self):return MyModel.objects.iterator()  # 流式查询,减少内存

总结

方法适用场景是否查询总数备注
pagination_class = None不需要分页❌ 不查询完全禁用分页
LimitOffsetPagination + count = None需要分页但不想计算总数❌ 不查询适用于无限滚动
CursorPagination大数据量分页❌ 不查询适用于无限滚动
手动覆盖 paginate_queryset完全自定义分页逻辑❌ 不查询适用于特殊需求
values() / iterator()优化查询性能取决于分页减少内存占用

如果你的 API 不需要分页,直接 pagination_class = None 是最简单的解决方案。
如果 需要分页但不想计算总数,建议使用 CursorPagination 或自定义 LimitOffsetPagination

http://www.dtcms.com/a/594508.html

相关文章:

  • HarmonyOS:弹性布局(Flex)
  • CANN在智能视频分析场景中的实践应用
  • 基于ESP32的宠物喂食小屋
  • 西昌有做网站的公司吗海南网站设计公司
  • Prometheus实战教程 - 服务发现
  • 卸载搜狗压缩软件
  • 企业网站制作免费下载效果图网站发帖平台
  • 做网站的时候用的什么框架app下载汅api免费下载大全视频
  • 鸿蒙应用开发之实现键值型数据库跨设备数据同步
  • 企业网站域名备案流程营销网红
  • 双擎驱动 AI 开发:智能体全流程评测 + 应用编排创新实践指南
  • 小杰-大模型(four)——RAG与Agent设计——Langchain-chain链
  • 吐鲁番大型网站建设平台素材库网站
  • mysql表的连接——内外连接
  • Java文件与IO流完全指南
  • 深圳建站公司兴田德润官网多少宁波网站推广建站
  • 学会网站建设能成为一项职业吗十大免费音乐网站
  • 零基础学JAVA--Day28(包装类+String类)
  • 网站的关键词排名怎么做怎么做网站优化的
  • 前端项目目录结构全解析
  • whisperX 安装及测试
  • 建立网站一般那些阶段成都工信部网站
  • 手机网站页面文字做多大网站开发课表查询
  • Python数据挖掘之聚类
  • 企业做网站需要注意事项广西建设安全员证查询网站
  • 网站统计WordPress轻量企业主题
  • 花都网站建设哪家好电子商务网站建设期末试题08答案
  • Node-RED生态中的Sparkplug B社区节点介绍
  • pyspark入门实操(收藏版)
  • 可以在家做兼职的网站做招聘信息的网站有哪些方面