当前位置: 首页 > 工具软件 > ApiView > 使用案例 >

Django REST Framework 之视图梳理APIView、GenericViewSet、ModelViewSet(超详细)

方宜
2023-12-01

APIView

DRF 为了更符合 restful api 规范,在 View 上层做了一层封装,就是 APIView,View 本身没有权限和认证以及限流等的操作,只做请求的分发,然后返回,里面就是一些简单的分发逻辑,但APIView不同,重写了 as_view方法,里面做了认证、限流、权限、渲染很多东西。
这种视图还不够通用,需要自己写一些分页、序列化、queryset 之类的东西。

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

ViewSet

他继承了 APIView和ViewSetMIxin, 他接收一个 action 关键字参数,作为覆盖 .as_view() 以便它接受一个 actions 关键字,该关键字将 HTTP 方法绑定到资源上的操作。
url 要这样写:MyViewSet.as_view({'get': 'list', 'post': 'create'})
这种视图一般不怎么常用,url 这样写看起来也不太好看,不优雅。

class ViewSet(ViewSetMixin, views.APIView):
    """
    The base ViewSet class does not provide any actions by default.
    """
    pass

class ViewSetMixin:
    """
    This is the magic.

    Overrides `.as_view()` so that it takes an `actions` keyword that performs
    the binding of HTTP methods to actions on the Resource.

    For example, to create a concrete view binding the 'GET' and 'POST' methods
    to the 'list' and 'create' actions...

    view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
    """

class UserViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving users.
    """
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)

可以这样写:
	from myapp.views import UserViewSet
	from rest_framework.routers import DefaultRouter
	
	router = DefaultRouter()
	router.register(r'users', UserViewSet)
	urlpatterns = router.urls

也可以这样:
	UserViewSet.as_view({'get': 'list'})
	UserViewSet.as_view({'get': 'retrieve'})

GenericViewSet

这个比上述两个要好一点,里面做了很多封装,如获取对象的、序列化的、分页的、queryset 等一系列操作,只需要指定好,在接口里面使用提供好的方法就行。
一般比较常用,封装了很多常用的内容。

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass


class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """
    # You'll need to either set these attributes,
    # or override `get_queryset()`/`get_serializer_class()`.
    # If you are overriding a view method, it is important that you call
    # `get_queryset()` instead of accessing the `queryset` property directly,
    # as `queryset` will get evaluated only once, and those results are cached
    # for all subsequent requests.
    # queryset
    queryset = None
    # 序列化
    serializer_class = None

    # If you want to use object lookups other than pk, set 'lookup_field'.
    # For more complex lookup requirements override `get_object()`.
    lookup_field = 'pk'
    lookup_url_kwarg = None

    # The filter backend classes to use for queryset filtering
    # 过滤器
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

    # The style to use for queryset pagination.
    # 分页
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

提供方法:
	get_queryset:获取集合
	get_object:获取一个model对象
	get_serializer:获取序列化器
	filter_queryset:筛选之后的queryset
	paginate_queryset:处理queryset
	get_paginated_response:返回分页结构的response
	

class UserGenericViewSet(GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    parser_classes = PageNumberPagination
	
	def post(self, request, *args, **kwargs):
        users = self.queryset()
        ser = self.get_serializer()
        return Response(ser.data)

mixins

提供了列表方法、创建、删除、获取、更新的方法,如果你这个功能只实现一个接口,如只有一个列表,直接继承list方法就行
这种只针对某一个模块有很少的功能时,可以采用

from rest_framework.mixins import 
ListModelMixin, CreateModelMixin, RetrieveModelMixin, 
UpdateModelMixin, DestroyModelMixin

class UserList(ListModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    parser_classes = PageNumberPagination

ModelViewSet

提供了增删改查四个方法,只需要定义好序列化,集合、分页器就好。
适合大模块,增删改查都有的,可以使用这个视图

class ModelViewSet(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

# 四个方法都有了,包括局部更新 patch, 工6个方法,还支持重写,完成自己想要的功能
class UserGenericViewSet(ModelViewSet):
     queryset = User.objects.all()
	 serializer_class = UserSerializer
     parser_classes = PageNumberPagination

总结

  1. apiview:提供了基础设施,增加了权限、认证、限流等相关功能,为扩展视图类提供了坚硬的基础,也可以在这个视图里面实现一些简单的接口,但不那么通用
  2. ViewSet:url 提供了action 关键字传参的方式,指定获取那个方法,不那么实用
  3. GenericViewSet:通用视图类,封装了集合、序列化、分页、筛选等操作,比较常用
  4. mixins:支持简单的增删改查操作,某个模块只有一个接口时,可以采用
  5. ModelViewSet:封装了增删改查四个方法,适合完整的大功能。

参考文献

django rest framework 中文网:https://q1mi.github.io/Django-REST-framework-documentation/
django rest framework 源码:https://blog.csdn.net/qq_39253370/article/details/124690671?spm=1001.2014.3001.5501

 类似资料: