如何在Django REST Framework的APIView中使用get_queryset及过滤分页功能
问题解决方案
核心问题解答
1. 能否直接在APIView中使用get_queryset?
可以但完全不推荐。APIView是DRF最底层的基础视图类,本身没有内置get_queryset、过滤、分页的相关处理逻辑,要手动实现的话需要自行编写过滤触发、分页响应格式化的全部代码,相当于重复造通用视图的轮子,代码冗余且容易出错。
2. APIView中能否同时配置filterset_class和分页功能?
可以但仍需要自行实现调用逻辑:你需要手动实例化filterset类处理查询集,手动调用分页类对结果做切片、生成标准化分页响应格式,本质是把DRF通用视图已经封装好的逻辑再重写一遍,没有实际价值。
3. 最优实现方案
使用GenericViewSet + 对应Mixin的组合,即可把所有CRUD操作、过滤分页能力全部整合到同一个视图类中,无需拆分接口,也无需重复编写基础逻辑。
具体实现代码
视图类代码
from rest_framework import viewsets, mixins, status from rest_framework.response import Response from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated import django_filters.rest_framework # 导入你项目中已有的模块 from .models import Lead from .serializers import LeadSerializer from .filters import LeadsFilter from .pagination import CustomPagination class LeadsViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): authentication_classes = (TokenAuthentication,) permission_classes = (IsAuthenticated,) queryset = Lead.objects.all().order_by('-date_created') serializer_class = LeadSerializer filter_backends = [django_filters.rest_framework.DjangoFilterBackend] pagination_class = CustomPagination filterset_class = LeadsFilter def get_queryset(self): # 简化后的自定义过滤逻辑,和原有效果一致 source = self.request.GET.get("source", None) lead_status = self.request.GET.get("lead_status", None) queryset = super().get_queryset() if source: source_values = source.split(",") queryset = queryset.filter(source__in=source_values) if lead_status: lead_status_values = lead_status.split(",") queryset = queryset.filter(lead_status__in=lead_status_values) return queryset # 保留你原有批量创建的逻辑 def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) self.perform_create(serializer) return Response(serializer.data, status=status.HTTP_201_CREATED)
路由配置
可以直接使用DRF的Router自动生成路由,替代原有三个路由:
from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r'lead', LeadsViewSet, basename='lead') urlpatterns = [ # 你的其他路由 ] + router.urls
如果不想用Router,也可以手动配置路由:
path('lead', LeadsViewSet.as_view({'get': 'list', 'post': 'create'}), name='leads-list'), path('lead/<int:pk>', LeadsViewSet.as_view({'get': 'retrieve', 'delete': 'destroy'}), name='leads-detail'),
方案优势
- 所有业务逻辑都在同一个视图类中,维护更方便,无需拆分单独的列表查询接口
- 直接复用DRF内置的过滤、分页、CRUD逻辑,无需手动重复实现,降低BUG率
- 路由更简洁,完全符合RESTful接口规范
内容的提问来源于stack exchange,提问作者Reactoo
相关产品推荐
相关产品推荐

