首页 > 编程语言 >02快速上手drf、CBV源码分析、APIVIEW源码分析

02快速上手drf、CBV源码分析、APIVIEW源码分析

时间:2024-05-15 16:55:36浏览次数:15  
标签:02 return APIVIEW self request 源码 time def view

快速上手drf、CBV源码分析、APiview源码分析

一、快速上手drf

【1】安装drf

pip install djangorestframework

注意:

  • 安装时不指定版本,默认下载最新版本
  • 每个版本有对应的解释器版本和django限制要求,下载时官网查看一下
  • 如果django版本是3以下,drf最新跟django3以下版本不兼容
版本要求:djangorestframework==3.12.4
	Python (3.5, 3.6, 3.7, 3.8, 3.9)
	Django (2.2, 3.0, 3.1)
    
版本要求:djangorestframework==3.11.2
	Python (3.5, 3.6, 3.7, 3.8)
	Django (1.11, 2.0, 2.1, 2.2, 3.0)

【2】配置,在settings.py中添加配置

INSTALLED_APPS = [
    ...
    # 注册rest_framework(drf)
    'rest_framework',
]

# drf相关配置以后编写在这里 
REST_FRAMEWORK = {
   
}

【3】使用原生django实现5个接口

  • 模型类 models
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
  • 配置路由(URL)
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view())
]

  • 视图类 views
class BookView(View):
    def get(self, request):
        # 获取所有图书
        book_list = models.Book.objects.all()

        # Object of type QuerySet is not JSON serializable,json不能序列化queryset对象
        
        return JsonResponse({"code": 100, "msg": "查询成功", "results": book_list})
      
       # 新增图书
    def post(self, request):
        # 反序列化,把前端传的数据转为python
        # request.body 是bytes格式,json格式不是字符串
        data = json.loads(request.body)
        book = models.Book.objects.create(**data)
        return JsonResponse({"code": 100, "msg": "新增成功", "results": {"name": book.name, "price": book.price}})


class BookDetailView(View):

    # 查单条
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        print(book_obj)
        return JsonResponse(
            {"code": 100, "msg": "查询成功", "results": {"name": book_obj.name, "price": book_obj.price}})

    # 删除一条
    def delete(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first().delete()
        if not book_obj:
            return JsonResponse({"code": 101, "msg": "删除失败"})
        return JsonResponse({"code": 100, "msg": "删除成功"})

    # 修改
    def put(self, request, pk):
        models.Book.objects.filter(pk=pk).update(price=1000)
        book_obj = models.Book.objects.filter(pk=pk).first()
        if not book_obj:
            return JsonResponse({"code": 101, "msg": "修改失败"})
        return JsonResponse(
            {"code": 100, "msg": "修改成功", "results": {"name": book_obj.name, "price": book_obj.price}})

补充:json可以序列化和反序列化的类型

             +---------------+-------------------+
    | JSON          | Python            |
    +===============+===================+
    | object        | dict              |
    +---------------+-------------------+
    | array         | list              |
    +---------------+-------------------+
    | string        | str               |
    +---------------+-------------------+
    | number (int)  | int               |
    +---------------+-------------------+
    | number (real) | float             |
    +---------------+-------------------+
    | true          | True              |
    +---------------+-------------------+
    | false         | False             |
    +---------------+-------------------+
    | null          | None              |
    +---------------+-------------------+

【4】使用drf实现5个接口

  • 路由
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
]
urlpatterns += router.urls
  • 视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
  • 序列化类
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

二、CBV源码分析

【1】cbv写法:

  • 视图中写视图类,继承View,写跟请求方式同名的方法
class BookView(View):
    def get(self,request):
        return 四件套
  • 在路径用写
path('books/', BookView.as_view())
  • 如上写法,为什么能够执行

【2】前置条件

  • 前端请求,一旦路径匹配成功,就会执行
    • BookView.as_view()(request传入,)
  • 入口在
    • BookView.as_view()--->执行结果---》View中有个as_view类的绑定方法
@classmethod
def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
      	# 类实力化得到对象
        # BookView类实例化得到对象
        self = cls(**initkwargs)
        # BookView类的dispatch
        res=self.dispatch(request, *args, **kwargs)
        return res
    return view
  • 执行结果是view 的内存地址: 请求来了,执行view(request)
path('books/', view)
  • 执行 View类中的as_view方法中的内层的view函数,路由匹配成功,本质是在执行
self.dispatch(request, *args, **kwargs)
  • self是谁的对象?
    • BookView的对象
  • 去BookView中dispatch,找不到
    • 去父类,View中找到了
  • View这个类的dispatch
def dispatch(self, request, *args, **kwargs):
    # request.method.lower() 如果是get请求,  ‘get’ 在这个列表里面
    if request.method.lower() in self.http_method_names:
        # handler=getattr(BookView的对象,'get')   
        # handler就是BookView类中的get方法
        handler = getattr(self, request.method.lower())
    else:
        handler = self.http_method_not_allowed
        # 执行 BookView类中的get方法 (request)
        return handler(request, *args, **kwargs)
  • 最终本质跟写fbv的执行流程一样

# 1 在路由中:path('index/',IndexView.as_view())

# 2 请求来了---》路由匹配成功--》执行 IndexView.as_view()(request)
	-看View类的as_view的返回结果[可以加括号执行]---》猜:函数内存地址
    
# 3 View类的as_view
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            self = cls(**initkwargs) # cls--》IndexView
            return self.dispatch(request, *args, **kwargs)
        return view
# 4 IndexView.as_view() 本质就是 --》view--》内存函数view

# 5 IndexView.as_view()(request)---》view(request)
# 6 本质 执行 self.dispatch--》self 是对象--》谁的对象?视图类的对象IndexView类的对象
	return self.dispatch(request, *args, **kwargs)

# 7 IndexView没有dispatch--》View类中的dispatch
	# request 当次请求的requets
    def dispatch(self, request, *args, **kwargs):
        #1 取出请求方式,转成小写,判断在不在列表中  get请求在
        #2 self.http_method_names 
        if request.method.lower() in self.http_method_names:
            # 3 反射:去 self IndexView类的对象中通过字符串get找属性或方法
            # 找到了get方法,赋值给了handler
            handler = getattr(self, request.method.lower())
        else:
            handler = self.http_method_not_allowed
            # 4 执行handler--》本质是get(request)
            # 执行了IndexView类中的get方法--》把request传进去了
        return handler(request, *args, **kwargs)
    
  

# 8 总结:
	路由匹配成功---》会根据请求方式执行视图类中跟请求方式同名的方法

三、APIView执行流程

drf中重写了 as_viewdispatch方法,其实就是在原来django的功能基础上添加了一些功能,例如:

  • as_view,免除了csrf 验证,一般前后端分离不会使用csrf token认证(后期会使用jwt认证)。

  • dispatch,内部添加了 版本处理、认证、权限、访问频率限制等诸多功能

  • 以后只要继承APIView的所有视图类的方法,都没有csrf的校验了

  • 以后只要继承APIView的所有视图类的方法 中的request是新的request了

  • 在执行视图类的方法之前,执行了三大认证(认证,权限,频率)

  • 期间除了各种错误,都会被异常捕获,统一处理

path('books/', views.BookView.as_view()),
# 1 请求来了---》会执行views.BookView.as_view()(request) ---》找as_view---》BookView找不到---》APIView中找---》as_view--->就干了一个事--》去除了csrf认证
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs) # 调用父类---》django原生View的as_view
        view=csrf_exempt(view) 
        # 等同于
        '''
        @csrf_exempt
        def view:
            pass
        '''
    
        return view             # 当前请求,去除掉了csrf认证
    
    
# 2 views.BookView.as_view()(request) 本质是执行  csrf_exempt(view)(request)
	-执行View的 中as_view内的view函数--》去除了csrf认证
# 3 本质在执行:self.dispatch(request, *args, **kwargs)
	BookView的dispatch---》BookView没有---》APIView找---》找到了
    def dispatch(self, request, *args, **kwargs):
        # 包装新的request
        request = self.initialize_request(request, *args, **kwargs)
        try:
            # 执行三大认证
            self.initial(request, *args, **kwargs)
            # 执行跟请求方式同名的视图类中得方法
            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
    
    
    
    
# 总结:
	1 APIView执行流程---》去除csrf--》执行了APIView的dispatch
    2 执行的as_view是APIView的as_view
    3 执行的dispatch也是APIView的dispatch
    
# 1 在路由中:path('books/', views.BookView.as_view()),请求来了
# 2 先看 as_view()---->APIView的 as_view---》as_view执行结果跟之前一样,去除了csrf认证
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs) # 调用父类的 as_view,view还是View的as_view
        # 以后所有请求,都不会做csrf认证了
        return csrf_exempt(view)
    
# 3 请求来了执行 views.BookView.as_view()(request)--->view(request)--->csrf_exempt(view)(request)--->内部核心---》return self.dispatch(request)
# 4 self 是 APIView类的对象---》APIView没有dispatch---》APIView的dispatch,核心代码如下
    def dispatch(self, request, *args, **kwargs):
        # 后续的request都是 initialize_request 返回结果--》新的request--》drf的Requet类的对象
        request = self.initialize_request(request, *args, **kwargs)
        # 新的request放到了 self.request中---》self是BookView类的对象
        # 后续视图类的方法中 可以直接 self.request取出 当次请求的request对象
        self.request = request

        try:
            # 执行了三大认证:
            '''
            self.perform_authentication(request)
            self.check_permissions(request)
            self.check_throttles(request)
            '''
            self.initial(request, *args, **kwargs)

            ###### 通过反射,去视图类中:BookView中执行跟请求方式同名的方法
            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
		   # request是新的Request类的对象了  get方法的第一个参数request也是新的
            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
    
    
    
# 5 看self.initialize_request 是APIView的
    def initialize_request(self, request, *args, **kwargs):
        # 类实例化得到对象,传入一些参数
        # Request类--》drf提供的类
        from rest_framework.request import Request
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    
  



# 只要继承APIView,以后方法中得request都变了,成了 rest_framework.request.Request 的对象了
	但是用起来,跟之前的一模一样
# 原来的是:django.core.handlers.wsgi.WSGIRequest 类的对象
    
    
    
    
    
    
# 总结:
	1 以后视图类方法中得request对象,变成了新的request,它是rest_framework.request.Request 的对象了,但是用起来跟之前一样
    2 把新的request对象,同时放到了 视图类的对象中  self.request = request  后续从视图类中可以直接通过 self.request取出来
    3 在执行视图类的方法之前,执行了三大认证
    4 如果三大认证或视图类的方法执行出错,会有全局异常处理
    5 以后所有的接口都去除了csrf认证

补充:装饰器原理

import time


def add(a, b):
    time.sleep(1)
    return a + b


#### 统计add的运行时间
# start_time = time.time()
# add(3, 4)
# end_time = time.time()
# print('运行时间是:', end_time - start_time)


### 写一个通用的,以后只要统计任意函数运行时间,都使用通用的--->改变了调用方式,不行
# def outer(func):
#     start_time = time.time()
#     func(3, 4)
#     end_time = time.time()
#     print('运行时间是:', end_time - start_time)
#
# outer(add)

def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print('运行时间是:', end_time - start_time)
        return res

    return inner


# inner=outer(add)
# 调用inner,就是执行,inner内部包了 add函数,inner叫闭包函数
# inner() # 改变了调用方式

# 继续优化
add = outer(add)

res = add(3, 4)  # add现在本质调用 inner,参数传给 inner,inner要能接收a,b 并且有返回结果
print(res)


# 以后想装饰哪个函数 得按如下操作,麻烦
# def ee():
#     print('ee')
#
# ee=outer(ee)
# ee()

# python提供了一个语法糖 @ ,以后只要按如下方式编写代码,就能实现上述功能
@outer  # 等同于  ee=outer(ee)   该语法糖会把被装饰器的函数ee,当做参数,传入outer,并且把outer的执行结果,返回赋值给ee
def ee():
    print('ee')


# 以后ee其实已经不是ee了,是inner了,执行ee本质在执行inner


#####上述是原理####

## 记忆
# 以后写它
def outer(func):
    def inner(*args, **kwargs):
        # 被装饰器函数,执行之前干事
        res = func(*args, **kwargs)
        #被装饰函数,执行之后干事情
        return res
    return inner

# 装饰某个函数
@outer
def add(a,b):
    time.sleep(1)
    return a+b

标签:02,return,APIVIEW,self,request,源码,time,def,view
From: https://www.cnblogs.com/Formerly/p/18194203

相关文章

  • MindSponge分子动力学模拟——自定义控制器(2024.05)
    技术背景分子动力学模拟中的控制器(Controller)可以被用于修改模拟过程中的原子坐标和原子速度等参量,从而达到控制系统特定参量的目的。例如控温器可以用于实现NVT系综,控压器可用于实现NPT系综。而在MindSponge分子动力学模拟框架下,控温控压都可以基于控制器Controller来实现。关于......
  • 2024-05-15:用go语言,考虑一个整数 k 和一个整数 x。 对于一个数字 num, 在其二进制表示
    2024-05-15:用go语言,考虑一个整数k和一个整数x。对于一个数字num,在其二进制表示中,从最低有效位开始,我们计算在x,2x,3x等位置处设定位的数量来确定其价值。举例说明,若对于x=1,num=13,则二进制表示为000001101,对应的价值为3。又如,当x=2,num=13,二进制表示依然为000001101,但对......
  • Spring源码分析:List集合注入
    pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://ma......
  • 基于Java网络书店商城设计实现(源码+lw+部署文档+讲解等)
    系统介绍:随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于网络书店商城当然也不能排除在外,随着网络技术的不断成熟,带动了网络书店商城,它彻底改变了过去传统的管理方式,不仅使服务管理难度变低了,还提升了管理的灵活性。这种个性化的平台特......
  • jwt揭秘(含源码示例和视频)
    jwt揭秘摘自:https://www.cnblogs.com/wupeiqi/p/11854573.html武沛齐博客JSONWebTokens,是一种开发的行业标准RFC7519,用于安全的表示双方之间的声明。目前,jwt广泛应用在系统的用户认证方面,特别是现在前后端分离项目。1.jwt认证流程在项目开发中,一般会按照上图所示......
  • P8803 [蓝桥杯 2022 国 B] 费用报销
    P8803[蓝桥杯2022国B]费用报销一、问题简析本题是一道01背包。重点是\(K\)的限制,使我们在取\(a_i\)时,不能无所顾忌地套用模板\(dp_{i-1,j-a_i.worth}+a_i.worth\)。我们必须找到上一张合法的\(a_j\),即\(a_j\)与\(a_i\)之间的日期不小于\(K\)。通过以下步骤确......
  • 【源码】蚁群算法TSP问题可视化
    ACO.Visualization项目本项目演示蚁群算法求解旅行商问题的可视化过程,包括路径上的信息素浓度、蚁群的运动过程等。项目相关的代码:https://github.com/anycad/ACO.Visualization注:本项目基于.NET8开发,需要安装VS2022最新版本。运行效果:https://www.bilibili.com/video/BV1Bf42......
  • 2024 年 5 月 14 日 周二 多云 热(270 字)
    正文今天好忙,一楼二楼来回跑。都17:57了,忽然打电话说要临时上来报一个表,我真服了。今晚罕见地只有我一个人吃饭。昨天练习完之后有一些进步。Routine里面加了三步。代价就是今天右手特别疼,因为昨天练习太久,掌骨关节在地上摁太久了。文件已经出了,明天似乎就要正......
  • 【2024-05-14】学习调整
    20:00这几天你一直对我板着脸。你大概觉得,我应该问问你,是哪只蚊子叮咬了你。                                                 ——约翰·沃尔夫冈·冯·歌德今天部门......
  • 【Elasticsearch】系统已经配置了JAVA_HOME,ElasticSearch源码还是操作gradle失败(JAVA_
    先看下报错内容吧,如下:FAILURE:Buildcompletedwith2failures.1:Taskfailedwithanexception.-----------*Where:Buildfile'/Users/liubolun/IdeaProjects/elasticsearch/benchmarks/build.gradle'line:20*Whatwentwrong:Aproblemoccurredevalu......