视图与路由
DRF 在 Django 原生视图基础上构建了一套完整的视图类体系,从底层的 APIView 到高层的 ModelViewSet,逐级封装重复逻辑,减少样板代码。本文从 Request / Response 对象讲起,依次介绍视图基类、通用视图、Mixin 扩展类、视图集和路由器的完整用法。
Request 与 Response
Request 对象
DRF 用 rest_framework.request.Request 替换 Django 原生的 HttpRequest,最重要的扩展:
request.data:解析后的请求体,支持 JSON、表单、文件,统一以字典形式访问(替代request.POST)。request.query_params:URL 查询字符串参数(替代request.GET)。request.user:经认证后的用户对象。request.auth:认证凭证(如 Token 值)。
from rest_framework.views import APIView
from rest_framework.response import Response
class DemoView(APIView):
def get(self, request):
# 获取 URL 参数:/api/items/?page=2
page = request.query_params.get("page", 1)
return Response({"page": page})
def post(self, request):
# 获取请求体(JSON 或表单均可)
name = request.data.get("name")
return Response({"received": name})Response 对象
rest_framework.response.Response 根据客户端 Accept 请求头自动选择渲染格式(浏览器返回 HTML 文档,其他客户端返回 JSON)。
Response(data, status=None, headers=None, content_type=None)data:Python 基础类型(字典、列表),不能是模型对象。status:HTTP 状态码,建议使用rest_framework.status中的常量。
from rest_framework import status
from rest_framework.response import Response
return Response({"message": "created"}, status=status.HTTP_201_CREATED)
return Response(None, status=status.HTTP_204_NO_CONTENT)常用状态码常量:HTTP_200_OK、HTTP_201_CREATED、HTTP_204_NO_CONTENT、HTTP_400_BAD_REQUEST、HTTP_401_UNAUTHORIZED、HTTP_403_FORBIDDEN、HTTP_404_NOT_FOUND。
APIView
APIView 是 DRF 所有视图的根基类,继承自 Django 的 View,额外提供:
- 自动解析请求体(JSON / 表单)。
- 自动渲染响应(JSON / 浏览器页面)。
- 统一捕获并格式化
APIException异常。 - 在
dispatch()前执行认证、权限检查和限流。
使用方式与 Django View 相同,按 HTTP 方法定义对应方法:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from students.models import Student
from .serializers import StudentModelSerializer
class StudentsAPIView(APIView):
"""列表接口:获取所有学生 / 创建学生"""
def get(self, request):
students = Student.objects.all()
serializer = StudentModelSerializer(instance=students, many=True)
return Response(serializer.data)
def post(self, request):
serializer = StudentModelSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = serializer.save()
return Response(StudentModelSerializer(instance).data, status=status.HTTP_201_CREATED)
class StudentAPIView(APIView):
"""详情接口:获取 / 更新 / 删除单个学生"""
def get(self, request, pk):
student = Student.objects.get(pk=pk)
return Response(StudentModelSerializer(student).data)
def put(self, request, pk):
student = Student.objects.get(pk=pk)
serializer = StudentModelSerializer(instance=student, data=request.data)
serializer.is_valid(raise_exception=True)
return Response(StudentModelSerializer(serializer.save()).data)
def delete(self, request, pk):
Student.objects.get(pk=pk).delete()
return Response(None, status=status.HTTP_204_NO_CONTENT)类属性可配置认证 / 权限 / 限流策略(覆盖全局配置):
class StudentAPIView(APIView):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
throttle_classes = [UserRateThrottle]GenericAPIView
GenericAPIView 继承自 APIView,增加了操作序列化器和数据库查询的方法,是所有通用视图的基础。
核心属性:
class StudentGenericView(GenericAPIView):
queryset = Student.objects.all() # 必填
serializer_class = StudentModelSerializer # 必填
# pagination_class = StandardPagination # 可选
# filter_backends = [DjangoFilterBackend] # 可选核心方法:
| 方法 | 说明 |
|---|---|
get_queryset() | 返回查询集,可重写以实现动态过滤 |
get_object() | 根据 URL pk 返回单个对象,不存在则自动返回 404 |
get_serializer() | 返回序列化器对象,自动注入 context(含 request) |
get_serializer_class() | 返回序列化器类,可重写以在同一视图中使用不同序列化器 |
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
class StudentGenericAPIView(GenericAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get(self, request):
serializer = self.get_serializer(instance=self.get_queryset(), many=True)
return Response(serializer.data)
def post(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=201)5 个 Mixin 扩展类
Mixin 类封装了常见 CRUD 操作,需配合 GenericAPIView 使用(因为它们调用 get_queryset、get_serializer 等方法)。
| Mixin 类 | 提供的方法 | 对应 HTTP 方法 | 状态码 |
|---|---|---|---|
ListModelMixin | list() | GET(列表) | 200 |
CreateModelMixin | create() | POST | 201 |
RetrieveModelMixin | retrieve() | GET(详情) | 200 / 404 |
UpdateModelMixin | update() | PUT / PATCH | 200 |
DestroyModelMixin | destroy() | DELETE | 204 / 404 |
示例:
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.generics import GenericAPIView
class StudentsView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class StudentView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get(self, request, pk):
return self.retrieve(request, pk)
def put(self, request, pk):
return self.update(request, pk)
def delete(self, request, pk):
return self.destroy(request, pk)通用视图子类
DRF 将常用的 Mixin 组合预先封装好,直接继承即可,无需再写 get/post 等方法:
from rest_framework.generics import (
ListAPIView, CreateAPIView, RetrieveAPIView,
UpdateAPIView, DestroyAPIView,
ListCreateAPIView, RetrieveUpdateDestroyAPIView,
)| 视图子类 | 提供的 HTTP 方法 |
|---|---|
ListAPIView | GET(列表) |
CreateAPIView | POST |
RetrieveAPIView | GET(详情) |
UpdateAPIView | PUT、PATCH |
DestroyAPIView | DELETE |
ListCreateAPIView | GET(列表)、POST |
RetrieveUpdateAPIView | GET、PUT、PATCH |
RetrieveDestroyAPIView | GET、DELETE |
RetrieveUpdateDestroyAPIView | GET、PUT、PATCH、DELETE |
class StudentsView(ListCreateAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
class StudentView(RetrieveUpdateDestroyAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializerViewSet 视图集
ViewSet 将一组相关接口合并到一个类中,方法名不再与 HTTP 方法绑定,而是通过 action(动作)映射。
ViewSet 与 GenericViewSet
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin
class StudentViewSet(GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer路由注册时显式指定 HTTP 方法与 action 的映射:
from django.urls import path, re_path
urlpatterns = [
path("students/", StudentViewSet.as_view({"get": "list", "post": "create"})),
re_path(r"students/(?P<pk>\d+)/", StudentViewSet.as_view({"get": "retrieve"})),
]ModelViewSet
ModelViewSet 已内置所有 5 个 Mixin,是最简洁的全 CRUD 方案:
from rest_framework.viewsets import ModelViewSet
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer自定义 action
使用 @action 装饰器在视图集中添加非标准操作:
from rest_framework.decorators import action
from rest_framework.response import Response
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
@action(methods=["get"], detail=False)
def top5(self, request):
"""获取最新添加的 5 个学生(路径格式:/students/top5/)"""
qs = self.get_queryset().order_by("-id")[:5]
return Response(self.get_serializer(qs, many=True).data)
@action(methods=["post"], detail=True)
def reset_password(self, request, pk):
"""重置指定学生密码(路径格式:/students/{pk}/reset_password/)"""
# detail=True 表示操作单条记录,URL 含 pk
...
return Response({"message": "密码已重置"})detail=False:路径为/students/top5/detail=True:路径为/students/{pk}/reset_password/
在视图方法中可通过 self.action 获取当前 action 名称,用于在 get_serializer_class() 等方法中根据动作返回不同序列化器。
Router 路由器
路由器自动为 ViewSet 生成 RESTful 路由,无需手写 urlpatterns。
使用方式
# students/urls.py
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register("students", views.StudentModelViewSet)
# router.register("prefix", ViewSetClass, basename="...")
urlpatterns = router.urls或将生成的路由追加到已有列表:
urlpatterns = [
path("other/", other_view),
]
urlpatterns += router.urlsDefaultRouter vs SimpleRouter
| 特性 | SimpleRouter | DefaultRouter |
|---|---|---|
| 列表 / 详情路由 | ✓ | ✓ |
| 根 API 列表页 | ✗ | ✓(访问 / 可看到所有接口) |
生产环境两者皆可,开发调试时 DefaultRouter 更便于查看所有已注册路由。
DefaultRouter 自动生成的路由结构:
GET /students/ → list
POST /students/ → create
GET /students/{pk}/ → retrieve
PUT /students/{pk}/ → update
PATCH /students/{pk}/ → partial_update
DELETE /students/{pk}/ → destroy使用 @action 装饰器声明的自定义 action 同样会被 Router 自动收录:
GET /students/top5/ → top5
POST /students/{pk}/reset_password/ → reset_password视图类选型
根据接口复杂度选择合适的层级:
| 场景 | 推荐方案 |
|---|---|
| 标准 CRUD,无定制 | ModelViewSet + Router |
| 部分 CRUD(如只读) | ReadOnlyModelViewSet 或 Mixin 组合 |
| 需要在同一 URL 支持多种序列化器 | 重写 get_serializer_class() |
| 接口逻辑与模型无关(聚合、统计等) | APIView / GenericAPIView |
| 自定义查询集(按用户过滤等) | 重写 get_queryset() |