跳至内容

视图与路由

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_OKHTTP_201_CREATEDHTTP_204_NO_CONTENTHTTP_400_BAD_REQUESTHTTP_401_UNAUTHORIZEDHTTP_403_FORBIDDENHTTP_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_querysetget_serializer 等方法)。

Mixin 类提供的方法对应 HTTP 方法状态码
ListModelMixinlist()GET(列表)200
CreateModelMixincreate()POST201
RetrieveModelMixinretrieve()GET(详情)200 / 404
UpdateModelMixinupdate()PUT / PATCH200
DestroyModelMixindestroy()DELETE204 / 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 方法
ListAPIViewGET(列表)
CreateAPIViewPOST
RetrieveAPIViewGET(详情)
UpdateAPIViewPUT、PATCH
DestroyAPIViewDELETE
ListCreateAPIViewGET(列表)、POST
RetrieveUpdateAPIViewGET、PUT、PATCH
RetrieveDestroyAPIViewGET、DELETE
RetrieveUpdateDestroyAPIViewGET、PUT、PATCH、DELETE
class StudentsView(ListCreateAPIView):
    queryset         = Student.objects.all()
    serializer_class = StudentModelSerializer

class StudentView(RetrieveUpdateDestroyAPIView):
    queryset         = Student.objects.all()
    serializer_class = StudentModelSerializer

ViewSet 视图集

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.urls

DefaultRouter vs SimpleRouter

特性SimpleRouterDefaultRouter
列表 / 详情路由
根 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()
最后更新于