CBV类视图继承

  • CBV:继承自View;注册的时候使用的as_view()

  • 入口

    • 不能使用请求方法的名字作为参数的名字

    • 只能接受已经存在的属性对应的参数

    • 定义了一个view

      • 创建了一个类视图对象

      • 保留,拷贝传递进来的属性和参数

      • 调用dispatch方法

        • 分发

        • 如果请求方法在我们的允许的列表中

          • 从自己这个对象中获取请求方法名字小写对应的属性,如果没有找到,会给一个默认http_method_not_allowded

        • 如果请求方法不在我们允许的列表中,直接就是http_method_not_allowed

        • 之后将参数传递,调用函数

  • 默认实现了options

    • 获取接口信息,可以获取接口都允许什么请求

  • 类视图继承自View;注册时使用as_view()
  1. from django.conf.urls import url
  2. from CBV import views
  3.  
  4. urlpatterns = [
  5. url(r'^hello/', views.HelloCBV.as_view(msg='Sleeping'), name='hello'),
  6. url(r'^books/', views.BooksCBV.as_view(), name='books'),
  7. ]
  • as_view 源码(base.py文件中)
  • 流程:as_view --> dispatch分发 --> 调用实现请求方法对应的函数名
  1. class View(object):
  2. """
  3. Intentionally simple parent class for all views. Only implements
  4. dispatch-by-method and simple sanity checking.
  5. """
  6.    # 允许的请求方法
  7. http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
  8.  
  9. def __init__(self, **kwargs):
  10. """
  11. Constructor. Called in the URLconf; can contain helpful extra
  12. keyword arguments, and other things.
  13. """
  14. # Go through keyword arguments, and either save their values to our
  15. # instance, or raise an error.
  16. for key, value in six.iteritems(kwargs):
  17. setattr(self, key, value)
  18.  
  19. @classonlymethod
  20. def as_view(cls, **initkwargs):
  21. """
  22. Main entry point for a request-response process.
  23. """
  24. for key in initkwargs:
              # 判断,不可以使用请求方法的名字作为参数名字
  25. if key in cls.http_method_names:
  26. raise TypeError("You tried to pass in the %s method name as a "
  27. "keyword argument to %s(). Don't do that."
  28. % (key, cls.__name__))
              # 只能接收类视图中已经存在的属性作为参数名(路由中的变量名要和视图函数中的属性名相同)
  29. if not hasattr(cls, key):
  30. raise TypeError("%s() received an invalid keyword %r. as_view "
  31. "only accepts arguments that are already "
  32. "attributes of the class." % (cls.__name__, key))
  33.      # 定义了一个view
  34. def view(request, *args, **kwargs):
  35. self = cls(**initkwargs)
  36. if hasattr(self, 'get') and not hasattr(self, 'head'):
  37. self.head = self.get # 默认get请求和head请求方式一样;支持get就支持head请求
  38. self.request = request # 将请求的参数,属性记录下来(三行)
  39. self.args = args
  40. self.kwargs = kwargs
              # 返回时调用dispatch方法
  41. return self.dispatch(request, *args, **kwargs)
  42. view.view_class = cls
  43. view.view_initkwargs = initkwargs
  44.  
  45. # take name and docstring from class
  46. update_wrapper(view, cls, updated=())
  47.  
  48. # and possible attributes set by decorators
  49. # like csrf_exempt from dispatch
  50. update_wrapper(view, cls.dispatch, assigned=())
  51. return view
  52.  
  53. def dispatch(self, request, *args, **kwargs):
  54. # Try to dispatch to the right method; if a method doesn't exist,
  55. # defer to the error handler. Also defer to the error handler if the
  56. # request method isn't on the approved list.
           # 将请求方法名变为小写,并判断请求方法名是否在允许的请求列表中
  57. if request.method.lower() in self.http_method_names:
              # 如果在允许的请求列表中,从自己的对象中去获取请求方法名字小写的属性,没有找到给变量一个默认值
  58. handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
  59. else: # 如果请求方法不在被允许的请求列表中,则http_method_not_allowd给变量
  60. handler = self.http_method_not_allowed
  61. return handler(request, *args, **kwargs)
  62.  
  63. def http_method_not_allowed(self, request, *args, **kwargs):
  64. logger.warning(
  65. 'Method Not Allowed (%s): %s', request.method, request.path,
  66. extra={'status_code': 405, 'request': request}
  67. )
  68. return http.HttpResponseNotAllowed(self._allowed_methods())

  69.     # 获取接口信息,获取接口都允许接收什么请求
  70. def options(self, request, *args, **kwargs):
  71. """
  72. Handles responding to requests for the OPTIONS HTTP verb.
  73. """
  74. response = http.HttpResponse()
  75. response['Allow'] = ', '.join(self._allowed_methods())
  76. response['Content-Length'] = ''
  77. return response
  78.  
  79. def _allowed_methods(self):
  80. return [m.upper() for m in self.http_method_names if hasattr(self, m)] 

类视图子类

[这些子类和模版是高度耦合的,在前后端分离中不会被使用。Mixin:只要继承中有此单词,就表示混合多继承]

TemplateView是多继承的子类,继承自:

  • View:分发函数:dispatch
  • ContextMixin:接收上下文(从视图函数传递到模板的内容)。函数:get_context_data
  • TemplateResponseMixin:将内容渲染到模板中。属性:template_name、template_engine、response_class、content_type。函数:render_to_response

base.py 源码分析

  1. # TemplateView
  2. class TemplateView(TemplateResponseMixin, ContextMixin, View):
  3. """
  4. A view that renders a template. This view will also pass into the context
  5. any keyword arguments passed by the URLconf.
  6. """
  7. def get(self, request, *args, **kwargs):
  8. context = self.get_context_data(**kwargs)
  9. return self.render_to_response(context)

views.py 使用

  1. from django.views.generic import TemplateView
  2.  
  3. # CBV继承TemplateView,实现了get请求,继承自:TemplateResponseMixin, ContextMixin, View(实现请求分发)
  4. class HelloTemplateView(TemplateView):
  5. template_name = 'hello.html'

 ListView是多继承子类。继承自:

  • MultipleObjectTemplateResponseMixin

    • TemplateResponseMixin

    • 获取模板名字,首先根据template_name获取;如果没找到,自己根据应用的名字,关联模型的名字,_list.html 去查找,App/book_list.html

  • BaseListView

    • MultipleObjectMixin

      • ContextMixin、get_queryset、model

    • View:默认实现了get,渲染成了response

views.py 使用

  1. from django.views.generic import ListView
  2. from App.models import Book
  3.  
  4. # CBV继承ListView,实现了get请求。获取一个集合数据
  5. # ListView继承自:MultipleObjectTemplateResponseMixin, BaseListView
  6. class HelloListView(ListView):
  7. template_name = 'BookList.html'
  8. model = Book

book.html

  1. <body>
  2. <ul>
  3. {% for book in object_list %}
  4. <li><a href="{% url 'cbv:single' pk=book.id %}">{{ book.b_name }}</a></li>
  5. {% endfor %}
  6. </ul>
  7. </body>

DetailView是多继承子类。继承自:

  • SingleObjectTemplateResponseMixin
    • TemplateResponseMixin:重写了获取模板名字的方法
  • BaseDetailView
    • View、SingleObjectMixin

views.py 使用

  1. from django.views.generic import DetailView
  2. from App.models import Book
  3.  
  4. # CBV继承DetailView。继承自SingleObjectTemplateResponseMixin, BaseDetailView
  5. class HeDetailView(DetailView):
  6. # template_name = 'Book.html' #. 如果不指定模版,自动去查找名字为:book_detail.html的模版
  7. # model = Book
  8. queryset = Book.objects.all()

urls.py

  1. from django.conf.urls import url
  2. from App import views
  3.  
  4. urlpatterns = [ # 单一实例:pk、slug
  5. url(r'^single/(?P<pk>\d+)/', views.HeDetailView.as_view(), name='single'),
  6. ]




APIView源码分析

APIView源码封装的类及用途

  • renderer_classes:            渲染的类
  • parser_classes:               解析转换的类
  • authentication_classes:    认证的类
  • throttle_classes:              节流的类、控制请求频率的[此接口每分钟请求多少次]
  • permission_classes:         权限的类
  • content_negotiation_class:内容过滤类
  • metadata_class:              元信息的类
  • versioning_class:             版本控制的类
  • as_view( )方法:调用父类中的as_view。对dispatch重写,主要做dispatch分发。

    • 重写的dispatch方法中的 initialize_request 方法初始化一个新的request。
    • 使用django的request构建了一个REST中的Request,
    • 将Django中的Request作为了自己的一个私有属性 _request
    • (若在rest_formwork中获取django的request,需要request._reuqest)
      • initial  初始化。获取接受的渲染、获取接受的类型、版本是否支持

        • perform_authentication:

          • 执行用户认证。request.user[.user中将方法改为属性,并进行认证]

            • 遍历用户认证器,如果认证成功会返回一个元组
            • 元组中的第一个元素就是 user
            • 第二个元素就是 auth [token]
        • check_permissions
          • 检查用户权限

            • 遍历权限检测器
            • 只要有一个权限检测没通过就直接显示权限被拒绝
            • 只有所有权限都满足,才算是拥有权限
        • check_throttles
          • 检测访问频率

            • 遍历频率限制器
            • 如果验证不通过,就需要等待
  • csrf_exempt
    • 所有APIView的子类都是csrf豁免的

Request源码分析

  • Request

    • 它是rest_framework的request。(rest_framework.request)

    • 将Django中的Request作为了自己的一个属性 _request

    • 属性和方法

      • content_type: 传输内容的类型

      • stream:          流

      • query_params:查询参数。[可以在post请求中获取GET参数][将Django中的request.GET方法改名为query_params]

      • data:              处理任意数据,同时兼容 POST,PUT,PATCH

      • user:              可以直接在请求上获取用户。[相当于在请求上添加一个用户对象属性]

      • auth:              认证。相当于请求上添加了一个属性,属性值是token

      • successful_authenticator:认证成功

Response源码分析

  • Response

    • 依然是HttpResponse的子类。只要类视图继承自APIView后,

    • Response自己封装的data 直接接受字典转换成JSON [ Response(data=request.data, status(状态码)=201) ]

    • 属性和方法

      • rendered_content:渲染的内容

      • status_text:状态码转成常量

        • 封装 status模块中,实际上就是一个常量类

针对视图函数的包装

  REST框架提供了两种可用于编写API视图的包装器(wrappers)

    • CBV:APIView
    • FBV:添加 @api_view装饰器;必须手动指定允许的请求方法
      • @api_view(http_method_names=['GET', 'POST'])
  1. from rest_framework import status
  2. from rest_framework.decorators import api_view
  3. from rest_framework.response import Response
  4. from RestSerializers.serializers import BookSerializer
  5.  
  6. @api_view(http_method_names=['GET', 'POST'])
  7. def books(request):
  8. print(type(request))
  9. if request.method == "GET":
  10. return Response(data={"msg": "get ok"})
  11. elif request.method == "POST":
  12. print(request.data)
  13. book_serializer = BookSerializer(data=request.data)
  14. if book_serializer.is_valid():
  15. book_serializer.save()
  16. return Response(data=book_serializer.data)
  17. return Response(data={'msg': 'error'}, status=status.HTTP_400_BAD_REQUEST)


APIView类视图子类

GenericAPIView继承自APIView;GenericAPIView是一个基类

  • generics包中。子类:

    • GenericAPIView

      • 增加的模型的获取操作

      • get_queryset:获取查询结果集

      • get_object:   获取单个对象。lookup_field 默认pk

      • get_serializer:序列化实例

      • get_serializer_class:     获取序列化类

      • get_serializer_context:  获取序列化上下文内容

      • filter_queryset:             对查询结果集过滤

      • paginator:                直接构件的分页器

      • paginate_queryset:        对查询结果集分页

      • get_paginated_response:获取分页后的结果

    • CreateAPIView

      • 创建的类视图。实现了post进行创建

      • 继承自GenericAPIView

      • 继承自CreateModelMixin

    • ListAPIView

      • 列表的类视图。实现了get

      • 继承自GenericAPIView

      • 继承自ListModelMixin

    • RetrieveAPIView

      • 查询单个数据的类视图。实现了get

      • 继承自GenericAPIView

      • 继承自RetrieveModelMixin

    • DestroyAPIView

      • 销毁数据的类视图,删除数据的类视图。实现了delete

      • 继承自GenericAPIView

      • 继承自DestroyModelMixin

    • UpdateAPIView

      • 更新数据的类视图。实现了put、patch

      • 继承自GenericAPIView

      • 继承自UpdateModelMixin

    • ListCreateAPIView

      • 获取列表数据,创建数据的类视图。实现了get、post

      • 继承自GenericAPIView

      • 继承自ListModelMixin

      • 继承自CreateModelMixin

    • RetrieveUpdateAPIView

      • 获取单个数据,更新单个数据的类视图。实现了get、put、patch

      • 继承自GenericAPIView

      • 继承自RetrieveModelMixin

      • 继承自UpdateModelMixin

    • RetrieveDestroyAPIView

      • 获取单个数据,删除单个数据。实现了get、delete

      • 继承自GenericAPIView

      • 继承自RetrieveModelMixin

      • 继承自DestroyModelMixin

    • RetrieveUpdateDestroyAPIView

      • 获取单个数据,更新单个数据,删除单个数据的类视图。实现了get、put、patch、delete

      • 继承自GenericAPIView

      • 继承自RetrieveModelMixin

      • 继承自UpdateModelMixin

      • 继承自DestroyModelMixin

  • mixins

    • CreateModelMixin

      • create

      • perform_create

      • get_success_headers

    • ListModelMixin

      • list:查询结果集,添加分页,帮你序列化

    • RetrieveModelMixin

      • retrieve:获取单个对象并进行序列化

    • DestroyModelMixin

      • destroy:

        • 获取单个对象

        • 调用执行删除

        • 返回Respon 状态码204

      • perform_destroy

        • 默认是模型的delete

        • 如果说数据的逻辑删除。重写进行保存

    • UpdateModelMixin

      • update:获取对象,合法验证;执行更新

      • perform_update

      • partial_update:差量更新,对应的就是patch

  • viewsets继承自:

    • ViewSetMixin:

      • 重写as_view。添加过滤和反向解析

    • GenericViewSet

      • 继承自GenericAPIView

      • 继承自ViewSetMixin

    • ViewSet

      • 继承自APIView

      • 继承自ViewSetMixin

      • 默认啥都不支持,需要自己手动实现

    • ReadOnlyModelViewSet

      • 只读的模型的视图集合

      • 继承自RetrieveModelMixin

      • 继承自ListModelMixin

      • 继承自GenericViewSet

    • ModelViewSet

      • 直接封装对象的所有操作

      • 继承自GenericViewSet

      • 继承自CreateModelMixin

      • 继承自RetrieveModelMixin

      • 继承自UpdateModelMixin

      • 继承自DestroyModelMixin

      • 继承自ListModelMixin

封装使用1:

  • user/serializers.py
  1. from rest_framework import serializers
  2. from user.models import User
  3. # ModelSerializer没有超链接的序列化
  4. class SingleUserSerializer(serializers.ModelSerializer):
  5. class Meta:
  6. model = User
  7. fields = ['id', 'username', 'password', 'phone',]
  • user/models.py
  1. from django.db import models
  2.  
  3. class User(models.Model):
  4. username = models.CharField(max_length=20, unique=True)
  5. password = models.CharField(max_length=128)
  6. phone = models.CharField(max_length=11)
  7. add_time = models.DateTimeField(auto_now=True)
  8.  
  9. class Meta:
  10. db_table = 'user'
  11.  
  12. def __str__(self):
  13. return self.username
  • user/views.py
  1. from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
  2. from user.models import User
  3. from user.serializers import SingleUserSerializer
  4.  
  5. class UserResouce(ListCreateAPIView):
  6. # 操作的模型
  7. queryset = User.objects.all()
  8. # 此模型对应的序列化类
  9. serializer_class = SingleUserSerializer
  10.  
  11. class UserResourcePro(RetrieveUpdateDestroyAPIView):
  12. queryset = User.objects.all()
  13. serializer_class = SingleUserSerializer
  • user/urls.py
  1. from django.urls import path
  2. from user.views import UserResouce, UserResourcePro
  3.  
  4. app_name = 'user'
  5. urlpatterns = [
  6. path('single', UserResouce.as_view(), name='single'),
  7. path('singlepro/<int:pk>', UserResourcePro.as_view(), name='singlepro'),
  8. ]

终极封装:

  • user/views.py
  1. from rest_framework.viewsets import ModelViewSet
  2. from user.models import User
  3. from user.serializers import SingleUserSerializer
  4.  
  5. class UserResourceVPro(ModelViewSet):
  6. queryset = User.objects.all()
  7. serializer_class = SingleUserSerializer
  • user/urls.py
  1. from django.urls import path, include
  2. from rest_framework.routers import DefaultRouter
  3. from user.views import UserResourceVPro
  4.  
  5. router = DefaultRouter()
  6. router.register(r'single', UserResourceVPro)
  7. # 此方式也可以获取单个对象:http://127.0.0.1:8000/user/single/2/
  8. # 主路由中
    8 urlpatterns = [
  9. path('', include(router.urls))
  10. ]

封装使用2:

  • urls.py
  1. from django.conf.urls import url, include
  2. from django.contrib import admin
  3. from App.urls import router
  4.  
  5. urlpatterns = [
  6. url(r'^admin/', admin.site.urls),
  7. url(r'^app/', include('App.urls')),
  8. url(r'^app/', include(router.urls)),
  9. ]
  • App/urls.py
  1. from django.conf.urls import url
  2. from rest_framework.routers import DefaultRouter
  3. from App import views
  4. from App.views import GameModelViewSet
  5.  
  6. urlpatterns = [
  7. url(r'^games/$', views.GamesView.as_view()),
  8. url(r'^games/(?P<pk>\d+)/$', views.GameView.as_view(), name='game-detail'),
  9. ]
  10.  
  11. 11 router = DefaultRouter()
  12. 12 router.register(r'progames', GameModelViewSet)
  • App/models.py
  1. from django.db import models
  2.  
  3. class Game(models.Model):
  4. g_name = models.CharField(max_length=32)
  5. g_price = models.FloatField(default=0)
  • App/serializers.py
  1. from rest_framework import serializers
  2. from App.models import Game
  3. # HyperlinkedModelSerializer带超链接的序列化
  4. class GameSerializer(serializers.HyperlinkedModelSerializer):
  5.  
  6. class Meta:
  7. model = Game
  8. fields = ('url', 'id', 'g_name', 'g_price')
  • App/views.py
  1. from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
  2. from rest_framework.viewsets import ModelViewSet
  3. from App.models import Game
  4. from App.serializers import GameSerializer
  5.  
  6. class GamesView(ListCreateAPIView):
  7. serializer_class = GameSerializer
  8. queryset = Game.objects.all()
  9.  
  10. class GameView(RetrieveUpdateDestroyAPIView):
  11. serializer_class = GameSerializer
  12. queryset = Game.objects.all()
  13.  
  14. class GameModelViewSet(ModelViewSet):
  15. serializer_class = GameSerializer
  16. queryset = Game.objects.all()

django 之(二) --- 源码分析的更多相关文章

  1. Django之DRF源码分析(二)---数据校验部分

    Django之DRF源码分析(二)---数据校验部分 is_valid() 源码 def is_valid(self, raise_exception=False): assert not hasat ...

  2. Django搭建及源码分析(三)---+uWSGI+nginx

    每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...

  3. Django如何启动源码分析

    Django如何启动源码分析 启动 我们启动Django是通过python manage.py runsever的命令 解决 这句话就是执行manage.py文件,并在命令行发送一个runsever字 ...

  4. Django rest framework源码分析(1)----认证

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  5. Django rest framework源码分析(一) 认证

    一.基础 最近正好有机会去写一些可视化的东西,就想着前后端分离,想使用django rest framework写一些,顺便复习一下django rest framework的知识,只是顺便哦,好吧. ...

  6. Django rest framework源码分析(3)----节流

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  7. Django rest framework 源码分析 (1)----认证

    一.基础 django 2.0官方文档 https://docs.djangoproject.com/en/2.0/ 安装 pip3 install djangorestframework 假如我们想 ...

  8. django CBV视图源码分析

    典型FBV视图例子 url路由系统 from django.conf.urls import url from django.contrib import admin from luffycity.v ...

  9. Django中间件部分源码分析

    中间件源码分析 中间件简介 中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Django的输入和输出.每个中间件组件都负责做一些特定的 ...

随机推荐

  1. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) C. p-binary

    链接: https://codeforces.com/contest/1247/problem/C 题意: Vasya will fancy any number as long as it is a ...

  2. Python 10.2.1

  3. 031_检测 MySQL 服务是否存活

    #!/bin/bash#host 为你需要检测的 MySQL 主机的 IP 地址,user 为 MySQL 账户名,passwd 为密码#这些信息需要根据实际情况修改后方可使用 host=127.0. ...

  4. leetcode解题报告(5):Longest Consecutive Sequence

    描述 Given an unsorted array of integers, find the length of the longest consecutive elements sequence ...

  5. python3实现互信息和左右熵的新词发现--基于字典树

    字典树 原来讲明白了剩下的就是具体实现了,最适合存储和计算词频的数据结构就是字典树,这里给一个讲解的很清楚的链接 具体代码 代码已开源,需要的点击这个Github

  6. 利用前端三大件(html+css+js)开发一个简单的“todolist”项目

    一.介绍 todolist,即待办事项.在windows android ios上参考微软家出的那个To-Do应用,大概就是那样的.我这个更简单,功能只有“待办” “已完成”两项,并且是在浏览器打开的 ...

  7. centos7初始化脚本(转)

    #!/bin/bash # 描述: CentOS 初始化脚本 # 加载配置文件 if [ -n "${1}" ];then /bin/} fi # 可接受配置(shell 变量格式 ...

  8. 【转】CAtlRegExp class .

    CAtlRegExp Class   CAtlRegExp 类用于表示并处理正则表达式.模板类,定义如下:     template < class CharTraits = CAtlRECha ...

  9. 数据库groub by分组后,把多行数据合并成一行数据(Oracle、Postgres)

    关键字 row_number() over (partition by)   例如,下面的数据, 这是按照name分组后,展示property值. 我们想得到这样的值; 第一步:将每一组的proper ...

  10. sql语句 基本

    1.sql不区分大小写,一般结尾要加分号: 2.select 列,列,列 from 表 3.distinct ,返回列中不同的值.需要哪个列不同,关键词哪个列 4.where子句,select 列 f ...