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