DRF之视图组

  • 先大概看一下这几个 视图类 的关系

    视图组.jpg

  • 使用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
      
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容