一、Generics:工具视图 generics 是工具视图,可以实现极简化接口编写操作。
工具视图都是 GenericAPIView 的子类,不同的子类继承不同工具类,重写请求方法。
1.群查与单增:ListCreateAPIView 查看源码 class ListCreateAPIView (mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): """ Concrete view for listing a queryset or creating a model instance. """ def get (self, request, *args, **kwargs ): return self.list (request, *args, **kwargs) def post (self, request, *args, **kwargs ): class ListCreateAPIView (mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): """ Concrete view for listing a queryset or creating a model instance. """ def get (self, request, *args, **kwargs ): return self.list (request, *args, **kwargs) def post (self, request, *args, **kwargs ): return self.create(request, *args, **kwargs)
代码实现 urls.py
from django.conf.urls import url, includefrom api import views urlpatterns = [ url(r'^v4/books/$' , views.BookListCreateView.as_view()), url(from django.conf.urls import url, includefrom api import views urlpatterns = [ url(r'^v4/books/$' , views.BookListCreateView.as_view()), url(r'^v4/books/(?P.*)/$' , views.BookListCreateView.as_view()), ]
工具视图的功能如果满足需求,只需要继承工具视图,添加 queryset,serializer_class
views.py
class BookListCreateView (ListCreateAPIView ): queryset = models.Book.objects.filter (is_delete=class BookListCreateView (ListCreateAPIView ): queryset = models.Book.objects.filter (is_delete=False ) serializer_class = serializers.BookModelSerializer
测试接口 群查
单增
入库成功
其他方法
根据上述源码分析与示例和下面的图示,我们可以很容易知道这些类的功能和用法
2.添加其他接口 代码实现 class BookListCreateView (ListCreateAPIView, UpdateAPIView): queryset = models.Book.objects.filter (is_delete=class BookListCreateView (ListCreateAPIView, UpdateAPIView): queryset = models.Book.objects.filter (is_delete=False ) serializer_class = serializers.BookModelSerializer
接口测试
修改成功
3.后续问题 但是上述虽然可以实现简单接口,但是有时候需求会很复杂。
比如,来自前端用户的数据格式并不是和我们规定的一样,有可能传来空值,错误字符等等。这就需要对 request.data 进行过滤,尤其是在入库的时候。
另外,如果数据有误,DRF 并不知道你的字段是哪出的问题,所以抛异常是只会是数据错误。我们需要对每个字段的每种错误类型给出对应的返回值。
可以在 UpdateModelMixin 源码中看到,request.data 并没有进行过滤。
class UpdateModelMixin : def update (self, request, *args, **kwargs ): partial = kwargs.pop('partial' , False ) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial)
二、Viewsets:视图集 1.简单使用 DRF 提供了 Viewsets.py 视图集,再次封装之前的操作。最主要的是,可以通过设置 请求-函数
映射关系,来将请求方式与原有方法或自定义方法对应执行。
查看源码
发现没有提供实际的方法
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. """ 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
但是看到它继承了 ViewSetMixin,GenericAPIView
查看 ViewSetMixin 类的 as_view 方法
GenericViewSet 和 ViewSet 都继承了 ViewSetMixin,as_view 可以配置 请求-函数
映射
比如view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
class ViewSetMixin : @classonlymethod def as_view (cls, actions=None , **initkwargs ): def view (request, *args, **kwargs ): self = cls(**initkwargs) self.action_map = actions for method, action in actions.items(): handler = getattr (self, action) setattr (self, method, handler) if hasattr (self, 'get' ) and not hasattr (self, 'head' ): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs)
代码实现 这样的好处是,各种需求的接口的请求方式都可以用不同函数定义返回值。比如十大接口对应十个函数,分别码代码。
views.py
class BookGenericViewSet (RetrieveModelMixin, ListModelMixin, GenericViewSet): queryset = models.Book.objects.filter (is_delete=False ) serializer_class = serializers.BookModelSerializer def get_list (self, request, *args, **kwargs ): return self.list (request, *args, **kwargs) def get_obj (self, request, *args, **kwargs ): class BookGenericViewSet (RetrieveModelMixin, ListModelMixin, GenericViewSet): queryset = models.Book.objects.filter (is_delete=False ) serializer_class = serializers.BookModelSerializer def get_list (self, request, *args, **kwargs ): return self.list (request, *args, **kwargs) def get_obj (self, request, *args, **kwargs ): return self.retrieve(request, *args, **kwargs)
urls.py
from django.contrib import adminfrom django.urls import pathfrom django.conf.urls import url, includefrom django.views.static import servefrom django.conf import settingsfrom api import views urlpatterns = [ url(r'^v5/books/$' , views.BookGenericViewSet.as_view({'get' :'get_list' })), url(r'^v5/books/(?P<pk>.*)/$' , views.BookGenericViewSet.as_view({'get' :from django.contrib import adminfrom django.urls import pathfrom django.conf.urls import url, includefrom django.views.static import servefrom django.conf import settingsfrom api import views urlpatterns = [ url(r'^v5/books/$' , views.BookGenericViewSet.as_view({'get' :'get_list' })), url(r'^v5/books/(?P<pk>.*)/$' , views.BookGenericViewSet.as_view({'get' :'get_obj' })), ]
2.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. """ 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
代码实现 views.py
class BookModelViewSet (ModelViewSet ): queryset = models.Book.objects.filter (is_delete=False ) serializer_class = serializers.BookModelSerializer def destroy (self, request, *args, **kwargs ): instance = self.get_object() if not instance: return APIResponse(1 , "Delete fail" ) instance.is_delete = True instance.save() return APIResponse(1 , class BookModelViewSet (ModelViewSet ): queryset = models.Book.objects.filter (is_delete=False ) serializer_class = serializers.BookModelSerializer def destroy (self, request, *args, **kwargs ): instance = self.get_object() if not instance: return APIResponse(1 , "Delete fail" ) instance.is_delete = True instance.save() return APIResponse(1 , "Delete successful" )
urls.py
from django.conf.urls import urlfrom api import views urlpatterns = [ url(r'^v6/books/$' , views.BookModelViewSet.as_view({'get' :'list' , 'post' :'create' })), url(r'^v6/books/(?P<pk>.*)/$' , views.BookModelViewSet.as_view({'get' : 'retrieve' , 'post' :'create' , 'put' : 'update' , 'patch' : 'partial_update' , 'delete' : from django.conf.urls import urlfrom api import views urlpatterns = [ url(r'^v6/books/$' , views.BookModelViewSet.as_view({'get' :'list' , 'post' :'create' })), url(r'^v6/books/(?P<pk>.*)/$' , views.BookModelViewSet.as_view({'get' : 'retrieve' , 'post' :'create' , 'put' : 'update' , 'patch' : 'partial_update' , 'delete' : 'destroy' })), ]
接口测试 群查
单查
单删 查看数据库
单增
入库成功
等等
总结 GenericAPIView 与 APIView 的区别与适用场景 1. GenericAPIView 视图类 GenericView 继承 GenericAPIView 视图类
适用于标准的接口请求,或实现标准的 Model 类操作接口。
案例: 用户查询时,发送 GET 请求,返回数据。
2. APIView 视图类 ViewSet 继承 APIView 视图类
实现不需要 Model 类操作,或非标准的 Model 类操作接口。比如,POST请求在标准的 Model 类操作用于新增接口,但以下案例并不符合这个标准。
案例 1: 请求手机验证码时,发送 POST 请求,不需要 Model 类的参与。
案例 2: 用户登录时,发送的 POST 请求,并不是完成数据的新增。POST 只是用于提交数据,返回值也不是登录用户信息,而是登录的认证信息。