【Django】DRF类视图整理

DRF 类视图整理

本文整理 Django REST framework 常见类视图,按层次和用途分类,并给出最小可运行的 viewurl 示例。本文默认面向前后端分离场景,前端通过 HTTP 调用这些接口。

快速对照表

类名 层次 主要用途 常用程度
views.APIView 基础 API 视图 手写请求处理 很常用
generics.GenericAPIView 带 queryset/serializer 的基础视图 自定义通用 API 常用
mixins.CreateModelMixin 行为 mixin 创建 常用
mixins.ListModelMixin 行为 mixin 列表 常用
mixins.RetrieveModelMixin 行为 mixin 详情 常用
mixins.UpdateModelMixin 行为 mixin 更新 常用
mixins.DestroyModelMixin 行为 mixin 删除 常用
generics.CreateAPIView 通用视图 创建 很常用
generics.ListAPIView 通用视图 列表 很常用
generics.RetrieveAPIView 通用视图 详情 很常用
generics.UpdateAPIView 通用视图 更新 常用
generics.DestroyAPIView 通用视图 删除 常用
generics.ListCreateAPIView 通用视图 列表 + 创建 很常用
generics.RetrieveUpdateAPIView 通用视图 详情 + 更新 常用
generics.RetrieveDestroyAPIView 通用视图 详情 + 删除 常用
generics.RetrieveUpdateDestroyAPIView 通用视图 详情 + 更新 + 删除 很常用
viewsets.ViewSet 资源视图集 自定义一组动作 常用
viewsets.GenericViewSet 资源视图集 mixin 组合 常用
viewsets.ModelViewSet 资源视图集 完整 CRUD 很常用
viewsets.ReadOnlyModelViewSet 资源视图集 只读接口 很常用

说明

  1. 在前后端分离项目里,最常用的一般是:APIViewListCreateAPIViewRetrieveUpdateDestroyAPIViewModelViewSet
  2. 如果你想完全掌控接口细节,用 APIView
  3. 如果你想减少样板代码,用 generics
  4. 如果你想把同一资源的多个动作统一管理,优先考虑 ViewSet / ModelViewSet
  5. 新人学习顺序建议:APIView -> GenericAPIView -> ListCreateAPIView -> RetrieveUpdateDestroyAPIView -> ModelViewSet

1. DRF 类视图整体层次

DRF 类视图可以粗略理解成下面这条线:

APIView -> GenericAPIView -> Mixins / Generics -> ViewSet / ModelViewSet

  • APIView:最基础的 API 类视图
  • GenericAPIView:增加 querysetserializer_class 等通用能力
  • Mixins:把列表、新增、更新、删除等行为拆成可复用模块
  • Generics:把 GenericAPIView + Mixins 组合成常用接口
  • ViewSet:把一组 CRUD 接口组织到一个类里

以下示例默认使用模型和序列化器:

python 复制代码
# models.py
from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100)
    published_date = models.DateField()

    def __str__(self):
        return self.title
python 复制代码
# serializers.py
from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title', 'author', 'published_date']

2. APIView

作用:最基础的 DRF 类视图,需要自己手动处理 get()post() 等方法。

python 复制代码
# views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework import views

from .models import Book
from .serializers import BookSerializer


class BookManualCreateView(views.APIView):
    def post(self, request, *args, **kwargs):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            book = serializer.save()
            return Response(BookSerializer(book).data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
python 复制代码
# urls.py
from django.urls import path
from .views import BookManualCreateView

urlpatterns = [
    path('books/manual-create/', BookManualCreateView.as_view(), name='book-manual-create'),
]

3. GenericAPIView

作用:在 APIView 基础上增加通用属性和方法,如:

  • queryset
  • serializer_class
  • get_queryset()
  • get_serializer()
  • get_object()

单独用它时,通常还需要自己写具体的 HTTP 方法。

python 复制代码
# views.py
from rest_framework import status
from rest_framework import generics
from rest_framework.response import Response

from .models import Book
from .serializers import BookSerializer


class BookGenericCreateView(generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
python 复制代码
# urls.py
from django.urls import path
from .views import BookGenericCreateView

urlpatterns = [
    path('books/generic-create/', BookGenericCreateView.as_view(), name='book-generic-create'),
]

4. Mixins 系列

Mixins 本身通常不会直接单独拿来当视图用,而是搭配 GenericAPIViewViewSet 使用。

4.1 CreateModelMixin

作用:提供创建对象能力,对应 create()

python 复制代码
from rest_framework import generics, mixins

from .models import Book
from .serializers import BookSerializer


class BookCreateMixinView(mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
python 复制代码
from django.urls import path
from .views import BookCreateMixinView

urlpatterns = [
    path('books/create-mixin/', BookCreateMixinView.as_view(), name='book-create-mixin'),
]

4.2 ListModelMixin

作用:提供列表查询能力,对应 list()

python 复制代码
from rest_framework import generics, mixins

from .models import Book
from .serializers import BookSerializer


class BookListMixinView(mixins.ListModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
python 复制代码
from django.urls import path
from .views import BookListMixinView

urlpatterns = [
    path('books/list-mixin/', BookListMixinView.as_view(), name='book-list-mixin'),
]

4.3 RetrieveModelMixin

作用:提供详情查询能力,对应 retrieve()

python 复制代码
from rest_framework import generics, mixins

from .models import Book
from .serializers import BookSerializer


class BookRetrieveMixinView(mixins.RetrieveModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
python 复制代码
from django.urls import path
from .views import BookRetrieveMixinView

urlpatterns = [
    path('books/<int:pk>/retrieve-mixin/', BookRetrieveMixinView.as_view(), name='book-retrieve-mixin'),
]

4.4 UpdateModelMixin

作用:提供更新能力,对应 update()partial_update()

python 复制代码
from rest_framework import generics, mixins

from .models import Book
from .serializers import BookSerializer


class BookUpdateMixinView(mixins.UpdateModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)
python 复制代码
from django.urls import path
from .views import BookUpdateMixinView

urlpatterns = [
    path('books/<int:pk>/update-mixin/', BookUpdateMixinView.as_view(), name='book-update-mixin'),
]

4.5 DestroyModelMixin

作用:提供删除能力,对应 destroy()

python 复制代码
from rest_framework import generics, mixins

from .models import Book
from .serializers import BookSerializer


class BookDestroyMixinView(mixins.DestroyModelMixin, generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
python 复制代码
from django.urls import path
from .views import BookDestroyMixinView

urlpatterns = [
    path('books/<int:pk>/destroy-mixin/', BookDestroyMixinView.as_view(), name='book-destroy-mixin'),
]

5. GenericAPIView + Mixins 组合视图

这些是 DRF 最常见的一组现成通用 API 视图。

5.1 CreateAPIView

作用:只负责创建。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookCreateAPIView(generics.CreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookCreateAPIView

urlpatterns = [
    path('books/create/', BookCreateAPIView.as_view(), name='book-create'),
]

5.2 ListAPIView

作用:只负责列表。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookListAPIView(generics.ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookListAPIView

urlpatterns = [
    path('books/list/', BookListAPIView.as_view(), name='book-list'),
]

5.3 RetrieveAPIView

作用:只负责单条详情。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveAPIView(generics.RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookRetrieveAPIView

urlpatterns = [
    path('books/<int:pk>/', BookRetrieveAPIView.as_view(), name='book-detail'),
]

5.4 UpdateAPIView

作用:只负责更新。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookUpdateAPIView(generics.UpdateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookUpdateAPIView

urlpatterns = [
    path('books/<int:pk>/update/', BookUpdateAPIView.as_view(), name='book-update'),
]

5.5 DestroyAPIView

作用:只负责删除。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookDestroyAPIView(generics.DestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookDestroyAPIView

urlpatterns = [
    path('books/<int:pk>/delete/', BookDestroyAPIView.as_view(), name='book-delete'),
]

5.6 ListCreateAPIView

作用:列表 + 创建。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookListCreateAPIView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookListCreateAPIView

urlpatterns = [
    path('books/', BookListCreateAPIView.as_view(), name='book-list-create'),
]

5.7 RetrieveUpdateAPIView

作用:详情 + 更新。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookRetrieveUpdateAPIView

urlpatterns = [
    path('books/<int:pk>/detail-update/', BookRetrieveUpdateAPIView.as_view(), name='book-detail-update'),
]

5.8 RetrieveDestroyAPIView

作用:详情 + 删除。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveDestroyAPIView(generics.RetrieveDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookRetrieveDestroyAPIView

urlpatterns = [
    path('books/<int:pk>/detail-delete/', BookRetrieveDestroyAPIView.as_view(), name='book-detail-delete'),
]

5.9 RetrieveUpdateDestroyAPIView

作用:详情 + 更新 + 删除。

python 复制代码
from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import path
from .views import BookRetrieveUpdateDestroyAPIView

urlpatterns = [
    path('books/<int:pk>/rud/', BookRetrieveUpdateDestroyAPIView.as_view(), name='book-rud'),
]

6. ViewSet 系列

ViewSet 适合把一组资源操作收拢到一个类里,常和路由器一起使用。

6.1 ViewSet

作用:最基础的 ViewSet,需要自己定义动作方法。

python 复制代码
from rest_framework import viewsets
from rest_framework.response import Response


class BookViewSet(viewsets.ViewSet):
    def list(self, request):
        return Response({'message': 'list books'})

    def retrieve(self, request, pk=None):
        return Response({'message': f'detail of {pk}'})
python 复制代码
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import BookViewSet

router = DefaultRouter()
router.register('books-viewset', BookViewSet, basename='books-viewset')

urlpatterns = [
    path('', include(router.urls)),
]

6.2 GenericViewSet

作用:结合 GenericAPIView 能力的 ViewSet,常和 mixins 搭配。

python 复制代码
from rest_framework import mixins, viewsets

from .models import Book
from .serializers import BookSerializer


class BookGenericViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import BookGenericViewSet

router = DefaultRouter()
router.register('books-generic-viewset', BookGenericViewSet, basename='books-generic-viewset')

urlpatterns = [
    path('', include(router.urls)),
]

6.3 ModelViewSet

作用:最常用的 ViewSet,默认提供完整 CRUD。

python 复制代码
from rest_framework import viewsets

from .models import Book
from .serializers import BookSerializer


class BookModelViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import BookModelViewSet

router = DefaultRouter()
router.register('books-model-viewset', BookModelViewSet, basename='books-model-viewset')

urlpatterns = [
    path('', include(router.urls)),
]

6.4 ReadOnlyModelViewSet

作用:只提供只读接口,通常是列表 + 详情。

python 复制代码
from rest_framework import viewsets

from .models import Book
from .serializers import BookSerializer


class BookReadOnlyModelViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
python 复制代码
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import BookReadOnlyModelViewSet

router = DefaultRouter()
router.register('books-readonly', BookReadOnlyModelViewSet, basename='books-readonly')

urlpatterns = [
    path('', include(router.urls)),
]

6.5 自定义路由@action

作用:在 ViewSet / ModelViewSet 现有 CRUD 之外,额外补充自定义接口。

常见有 3 种情况:

  1. detail=True,不写 url_path,默认使用方法名作为路径。
  2. detail=True,自定义 url_path,面向单个对象。
  3. detail=False,自定义 url_path,面向整个集合。
python 复制代码
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

from .models import Book
from .serializers import BookSerializer


class BookActionViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    @action(detail=True, methods=['post'])
    def publish(self, request, pk=None):
        book = self.get_object()
        return Response({'message': f'publish book {book.pk}'}, status=status.HTTP_200_OK)

    @action(detail=True, methods=['post'], url_path='publish-now')
    def publish_now(self, request, pk=None):
        book = self.get_object()
        return Response({'message': f'publish now {book.pk}'}, status=status.HTTP_200_OK)

    @action(detail=False, methods=['get'], url_path='recent')
    def recent_books(self, request):
        return Response({'message': 'recent books'}, status=status.HTTP_200_OK)
python 复制代码
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .views import BookActionViewSet

router = DefaultRouter()
router.register('books-actions', BookActionViewSet, basename='books-actions')

urlpatterns = [
    path('', include(router.urls)),
]

对应路由通常会是:

  • POST /books-actions/{pk}/publish/
  • POST /books-actions/{pk}/publish-now/
  • GET /books-actions/recent/

补充说明:

  • detail=True 表示这是"单对象路由",URL 里会带主键。
  • detail=False 表示这是"集合路由",URL 里不带主键。
  • url_path 用来控制 URL 路径片段;如果不写,默认使用方法名。
  • 如果还需要控制反向解析名字,可以继续传 url_name='xxx'