RESTful架构和DRF进阶:CBV实战与高级特性
在上一节中,我们讲解了基于FBV(函数视图)实现REST风格API的方法,本节将聚焦DRF的进阶用法——通过CBV(类视图)快速开发接口,并详解分页、数据筛选等核心功能,帮助你在实际开发中兼顾效率与灵活性。
一、基于CBV实现REST接口
CBV(Class-Based View)是DRF中更高效的接口开发方式,通过继承DRF封装的视图类,可大幅减少重复代码;相比之下,FBV(Function-Based View)虽更灵活,但需要手动编写更多逻辑。下面以学科接口为例,讲解CBV的具体用法。
1. 继承APIView子类快速实现单一功能接口
DRF的APIView提供了多个子类(如ListAPIView、CreateAPIView等),每个子类封装了特定HTTP方法的处理逻辑,可直接复用。
步骤1:编写视图类
修改polls/views.py,删除原有的show_subjects函数视图,新增继承ListAPIView的类视图(仅支持GET请求获取学科列表):
```Pythonfrom rest_framework.generics import ListAPIViewclassSubjectView(ListAPIView):# 通过queryset指定如何获取学科数据 queryset = Subject.objects.all()# 通过serializer_class指定如何序列化学科数据 serializer_class = SubjectSerializer
- •
ListAPIView是APIView的子类,已内置get方法,无需手动编写即可处理 GET 请求; - • 核心只需配置两个属性:
queryset(数据来源)、serializer_class(序列化规则)。
步骤 2:配置 URL 映射
修改polls/urls.py,将类视图映射到 URL(需调用as_view()方法转换为可调用视图):
urlpatterns = [ path('api/subjects/', SubjectView.as_view()), ]
补充:APIView 核心子类说明DRF 为常见的接口场景封装了多个APIView子类,可按需选择:
2. 继承 ModelViewSet 实现全功能接口
如果需要为学科接口同时支持 GET(列表 / 详情)、POST(新增)、PUT/PATCH(更新)、DELETE(删除)等所有操作,推荐继承ModelViewSet—— 它整合了上述所有功能,无需编写额外逻辑。
步骤 1:编写视图类
修改polls/views.py,删除SubjectView,新增SubjectViewSet类:
from rest_framework.viewsets import ModelViewSetclassSubjectViewSet(ModelViewSet): queryset = Subject.objects.all() serializer_class = SubjectSerializer
步骤 2:ModelViewSet 核心原理
ModelViewSet通过继承多个 Mixin 类实现全功能支持,其源码结构如下:
classModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):""" A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """pass
每个 Mixin 类对应一个核心功能,ModelViewSet直接整合所有能力,只需配置queryset和serializer_class即可完成全功能接口开发。
步骤 3:配置 URL 映射(路由注册)
ModelViewSet包含多个接口逻辑,需通过 DRF 的路由器(Router)注册 URL,而非直接映射:
from rest_framework.routers import DefaultRouterrouter = DefaultRouter()router.register('api/subjects', SubjectViewSet)urlpatterns += router.urls
除了ModelViewSet类外,DRF还提供了一个名为ReadOnlyModelViewSet 的类,从名字上就可以看出,该类是只读视图的集合,也就意味着,继承该类定制的数据接口只能支持GET请求,也就是获取单个资源和资源列表的请求。
二、DRF 数据分页:控制列表数据返回量
获取资源列表时,一次性返回所有数据会导致接口响应慢、前端渲染卡顿,因此分页是 REST 接口的必备功能。DRF 提供了多种分页方式,可全局配置或自定义。
1. 全局默认分页配置
在 Django 项目的settings.py中配置REST_FRAMEWORK,设置全局默认分页规则:
REST_FRAMEWORK = {'PAGE_SIZE': 10,'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination'}
配置后,所有基于 DRF 的列表接口都会自动分页,返回格式如下:
{"count":100,// 总数据量"next":"http://example.com/api/subjects/?page=2",// 下一页URL"previous":null,// 上一页URL(第一页为null)"results":[/* 分页数据列表 */]}
2. DRF 内置分页器说明
DRF 提供了 3 种常用分页器,可根据业务场景选择:
| | |
| 基于页码分页(?page=2&page_size=10) | |
| 基于偏移量分页(?limit=10&offset=10) | |
| | |
3. 自定义分页器(视图级别)
如果需要为特定接口定制分页规则(如每页 5 条、支持自定义页大小),可编写自定义分页类,并在视图中指定:
步骤 1:编写自定义分页类
from rest_framework.pagination import PageNumberPaginationclassCustomizedPagination(PageNumberPagination):# 默认页面大小 page_size = 5# 页面大小对应的查询参数 page_size_query_param = 'size'# 页面大小的最大值 max_page_size = 50
步骤 2:在视图中使用自定义分页器
classSubjectView(ListAPIView):# 指定如何获取数据 queryset = Subject.objects.all()# 指定如何序列化数据 serializer_class = SubjectSerializer# 指定如何分页 pagination_class = CustomizedPagination
4. 取消分页
如果某接口不需要分页,可将pagination_class设为None:
classSubjectView(ListAPIView): queryset = Subject.objects.all() serializer_class = SubjectSerializer pagination_class = None# 取消分页
三、DRF 数据筛选:精准获取目标数据
实际开发中,接口常需要根据条件筛选数据(如 “根据学科编号获取对应老师”),DRF 支持两种核心筛选方式:重写get_queryset方法、使用django-filter扩展。
1. 重写 get_queryset 方法(基础筛选)
通过重写视图类的get_queryset方法,可从请求中获取筛选条件,动态过滤数据。以 “根据学科编号筛选老师” 为例:
步骤 1:编写老师视图类
classTeacherView(ListAPIView): serializer_class = TeacherSerializerdefget_queryset(self): queryset = Teacher.objects.defer('subject')try: sno = self.request.GET.get('sno', '') queryset = queryset.filter(subject__no=sno)return querysetexcept ValueError:raise Http404('No teachers found.')
步骤 2:配置 URL
path('api/teachers/', TeacherView.as_view()),
前端可通过/api/teachers/?sno=1获取编号为 1 的学科下的所有老师。
2. 使用 django-filter 扩展(高级筛选)
对于复杂筛选场景(多条件、模糊查询等),推荐使用django-filter扩展,配合 DRF 实现更灵活的筛选:
步骤 1:安装依赖
pip install django-filter
步骤 2:配置 DRF 筛选后端
# settings.pyINSTALLED_APPS = [# 其他应用'django_filters',]REST_FRAMEWORK = {'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],}
步骤 3:在视图中配置筛选字段
from rest_framework.generics import ListAPIViewfrom django_filters.rest_framework import DjangoFilterBackendfrom .models import Teacherfrom .serializers import TeacherSerializerclassTeacherView(ListAPIView): queryset = Teacher.objects.all() serializer_class = TeacherSerializer filter_backends = [DjangoFilterBackend] filter_fields = ['subject__no', 'sex'] # 支持按学科编号、性别筛选
前端可通过/api/teachers/?subject__no=1&sex=1筛选 “学科 1 的男老师”,无需手动编写筛选逻辑。
总结
- 1. DRF 的 CBV 模式通过继承
APIView子类 /ModelViewSet,可快速实现 REST 接口,相比 FBV 更高效、代码更简洁; - 2.
ModelViewSet整合了增删改查全功能,配合 DRF 路由器可自动生成 URL,大幅降低开发成本; - 3. DRF 内置多种分页器,支持全局配置和视图级自定义,是控制列表数据返回量的核心手段;
- 4. 数据筛选可通过重写
get_queryset(基础场景)或django-filter(复杂场景)实现,满足不同业务的筛选需求。