关注

【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 接口组织到一个类里

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

# 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
# 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() 等方法。

# 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)
# 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 方法。

# 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)
# 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()

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)
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()

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)
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()

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)
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()

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)
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()

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)
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

作用:只负责创建。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


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

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

5.2 ListAPIView

作用:只负责列表。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


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

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

5.3 RetrieveAPIView

作用:只负责单条详情。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


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

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

5.4 UpdateAPIView

作用:只负责更新。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


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

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

5.5 DestroyAPIView

作用:只负责删除。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


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

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

5.6 ListCreateAPIView

作用:列表 + 创建。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


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

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

5.7 RetrieveUpdateAPIView

作用:详情 + 更新。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
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

作用:详情 + 删除。

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveDestroyAPIView(generics.RetrieveDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
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

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

from rest_framework import generics

from .models import Book
from .serializers import BookSerializer


class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
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,需要自己定义动作方法。

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}'})
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 搭配。

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
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。

from rest_framework import viewsets

from .models import Book
from .serializers import BookSerializer


class BookModelViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
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

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

from rest_framework import viewsets

from .models import Book
from .serializers import BookSerializer


class BookReadOnlyModelViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
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,面向整个集合。
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)
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'

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/SDKL_YI/article/details/162232102

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--