-
先大概看一下这几个 视图类 的关系
-
使用
APIView
,定义方法views中: from rest_framework.views import APIView class BookView(APIView): # 查看所有 def get(self, request): pass # 添加单条 def post(self, request): pass class SBookView(APIView): # 查看单条 def get(self, request, id): pass # 更改单条 def put(self, request, id): pass # 删除单条 def delete(self, request, id): pass 对应的url: url(r'^book/$', views.BookView.as_view()), # 必须加上结尾符,否则匹配不到下面 url(r'^book/(\d+)/', views.SBookView.as_view()),
-
进一步封装
views1中: from rest_framework import generics # 处理增删改查查的五个类,每个类里都有各自的处理方法 from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \ RetrieveModelMixin from app01.models import Publish class PublishSerializer(serializers.ModelSerializer): class Meta: model = Publish fields = '__all__' class PublishView(ListModelMixin, CreateModelMixin, generics.GenericAPIView): # 【APIView由这个类里继承】 queryset = Publish.objects.all() # 【这两个变量必须交这个名字,因为继承类里面要拿这个变量去处理】 serializer_class = PublishSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) # 在ListModelMixin里有这个方法 def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) # 在CreateModelMixin里有这个方法 class SPublishView(UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, generics.GenericAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer def get(self,request,*args,**kwargs): return self.retrieve(request,*args,**kwargs) # 在 RetrieveModelMixin里有这个方法 def put(self,request,*args,**kwargs): return self.update(request,*args,**kwargs) # 在 UpdateModelMixin里有这个方法 def delete(self,request,*args,**kwargs): return self.destroy(request,*args,**kwargs) # 在 DestroyModelMixin里有这个方法 对应的url: url(r'^publishes/$',views1.PublishView.as_view()), url(r'^publishes/(?P<pk>\d+)/', views1.SPublishView.as_view()), # 参数必须以此命名,因为函数处理时就接收这个参数
-
再一步封装
views2中: from rest_framework import generics from app01.models import Author class AuthorSerializer(serializers.ModelSerializer): class Meta: model = Author fields = '__all__' # 简直太省了,把get和post等方法都封装进了类里。 class AuthorsView(generics.ListCreateAPIView): # 这个类里提供get,post两个方法 queryset = Author.objects.all() serializer_class = AuthorSerializer class SAuthorsView(generics.RetrieveUpdateDestroyAPIView): # 这个类提供了get/1,put/1,delete/1。3个方法 queryset = Author.objects.all() serializer_class = AuthorSerializer # 上面两个类对之前的类又进行了封装 对应的url: url(r'^authors/$',views2.AuthorsView.as_view()), url(r'^authors/(?P<pk>\d+)/', views2.SAuthorsView.as_view()),
-
终极封装
views3中: from rest_framework.viewsets import ModelViewSet from app01.models import Author from app01.serializer import AuthorSerializer class AuthorsView(ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorSerializer 对应的url: url(r'^authorsss/$',views3.AuthorsView.as_view({'get':'list','post':'create'})), url(r'^authorsss/(?P<pk>\d+)/',views3.AuthorsView.as_view({'get':'retrieve','delete':'destroy','put':'update'})) # ↑上面的as_view中的参数必须以此命名
封装的越深,约束性越大,功能的扩展性就越差,所以最后可根据不同的业务逻辑去使用不同的方法。
- ModelViewSet源码流程
-
1,继承
ModelViewSet
class AuthorsView(ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorSerializer
-
2,先进去,看看里面的结构,
继承了哪些类
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
-
3,前5个类,分别封装了几种不同的操作方法,最后一个
GenericViewSet
功能强大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
-
4,左边的
ViewSetMixin
,有as_view
方法,将方法赋给其对象class ViewSetMixin(object): # 如果使用ModelViewSet,则执行的as_view就是ViewSetMixin中的as_view方法。 @classonlymethod def as_view(cls, actions=None, **initkwargs): # 如果没有定义,就报错,所以必须那样写。 if not actions: raise TypeError("The `actions` argument must be provided when " "calling `.as_view()` on a ViewSet. For example " "`.as_view({'get': 'list'})`") def view(request, *args, **kwargs): self = cls(**initkwargs) self.action_map = actions for method, action in actions.items(): # 核心代码:把参数里面的键值对,以self.method = ...的形式,变成了self的属性 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) return csrf_exempt(view)
-
5,右边的
generics.GenericAPIView
继承了APIView
class GenericAPIView(views.APIView):
-
6,
APIView
中有dispatch
方法def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs # 路由中传的命名参数 # 1,重新封装request对象 request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: # 2,认证,权限,频率 self.initial(request, *args, **kwargs) # 【用字符串,反射self里面对应的方法,此步之后就有了self.get/self.post】 # Get the appropriate handler method if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) # 【如果没有找到,就走这一个】 else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
-