drf知识--02

news2024/9/25 7:18:06

APIView执行流程分析

源码分析:
# 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)

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

Request对象分析(难--记总结)

# 分析APIVIew时,分析出,以后request都是新的request

        是drf提供的Request的对象   from rest_framework.request import Request

# 源码解析之 __init__--->老的request在新的内部---》request._request:
# 先看 __init__--->类实例化得到对象时,对对象进行初始化,往对象中放数据
    def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):
        # 传入的request是老的,django原生的request
        # 放到了self._request,self 是新的request类的对象
        self._request = request
        self._data = Empty
        self._files = Empty                                        
        request = self.initialize_request(request, *args, **kwargs)  # 前面是新的,后面是老的
        return Request(request)    # 老的

# 以后用新的跟用老的一样, 是因为新的request包含了老的,并且还有自己的新功能
# 魔法方法:在类内部,以 __开头  __结尾的方法, 在某种情况下会自动调用,他们称之为魔法方法
            __init__:  在调用类名()会自动触发
            __str__:   print对象时自动触发  
      还有很多,所有类都继承object类,它都在object类中


  #  __getattr__ :通过对象.属性 ,属性不存在时会触发

def __getattr__(self, attr):
    try:
    # 通过反射,去老的中取,能取到就返回,取不到,执行except代码,再取不到就报错
        return getattr(self._request, attr)
    except AttributeError:
        return self.__getattribute__(attr)

# APIView中的request :
    1 新的request中有老的requet, 在request._request
    2 新的request 多了data属性,客户端提交的请求体中得数据

                无论以那种方式编码,都在request.data中
    3 其他的使用,跟之前老request一模一样

request.method
request.path
request.POST
request.GET
request.FILES
。。。

# 总结:
1 原生django的post方法处理提交数据,只能处理urlencoded和form-data编码

                从request.POST中取
2 原生djagno的put处理不了提交的数据,需要我们自己从body中取出来处理
        -分不同编码格式:
            urlencoded:name=lqz&age=19     # 用字符串切割
            json:{"xxz":"xx","yyz":"yyy"}           # 要用json.loads  进行反序列化          
3 原生django不能处理json提交的数据,需要自己做(put,post)
4 新的request解决了所有问题     # request.data   

序列化类介绍

# 序列化类可以干的事:
            序列化qs对象,单个对象,做序列化给前端
            前端传入数据,校验数据是否合法
           反序列化,前端传入数据,存到数据库中

# 继承APIView+Response实现 Publish的5个接口

class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        l = []
        for publish in publish_list:
            l.append({'name': publish.name, 'addr': publish.addr})
        return Response({'code': 100, 'msg': '查询所有成功', 'results': l})

    def post(self, request):
        # 如果是urlencoded编码,这种方式不行 publish = Publish.objects.create(**request.data)
        publish = Publish.objects.create(name=request.data.get('name'), addr=request.data.get('addr'))
        return Response({'code': 100, 'msg': '新增成功', 'results': {'name': publish.name, 'addr': publish.addr}})
class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        return Response(
            {'code': 100, 'msg': '查询单条成功', 'results': {'name': publish.name, 'addr': publish.addr}})

    def put(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        publish.name = request.data.get('name')
        publish.addr = request.data.get('addr')
        publish.save()
        return Response({'code': 100, 'msg': '修改成功', 'result': {'name': publish.name, 'addr': publish.addr}})

    def delete(self, request, pk):
        Publish.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

序列化类的使用

#  drf 提供的序列化器,实现序列化,反序列化和数据校验 

# 使用步骤:
1、写个py文件,叫serializer.py
 2、写个类,继承serializers.Serializer
3、在类中写要序列化的字段:

class PublishSerializer(serializers.Serializer):
     name = serializers.CharField()     # 写字段,要序列化的字段
     addr = serializers.CharField()
     id = serializers.IntegerField()

4、在视图类中使用,完成  序列化:

多条:
ser = PublishSerializer(instance=publish_list, many=True)      
ser.data  序列化后的数据
单条:
ser = PublishSerializer(instance=publish)      
ser.data  序列化后的数据

序列化类快速使用

# 视图类:
from .serializer import PublishSerializer
class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ser = PublishSerializer(instance=publish_list, many=True)  # 如果序列化多条,要many=True
        return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data})

class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ser = PublishSerializer(instance=publish)  # 单个不写many=True
        return Response(
            {'code': 100, 'msg': '查询单条成功', 'results': ser.data})
# 序列化类:
from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
    # 写字段,要序列化的字段
    name = serializers.CharField()
    # addr = serializers.CharField()
    id = serializers.IntegerField()
# 路由
urlpatterns = [
    path('publish/', views.PublishView.as_view()),
    path('publish/<int:pk>', views.PublishDetailView.as_view()),
]

序列化类反序列化校验

# 序列化类中可以做字段校验, 三层
 第一层:字段自己的serializers.CharField(max_length=12,min_length=3)
 第二层:局部钩子

def validate_name(self, name):
     if name.startswith("sb"):
         # 抛异常
         raise ValidationError('不能以sb开头')
     return name

def validate_addr(self, addr):
     if 'sb' in addr:
         # 抛异常
         raise ValidationError('地址中不能有sb')
     return addr

第三层:全局钩子(注意:前端多传的,这里不会有) 

def validate(self, attrs):
    print(attrs)
    # 多个字段同时校验
    # 出版社名和地址不能一样---》出版社前3个字不能和地址前3个字一样
    if attrs.get('name')[:3] == attrs.get('addr')[:3]:
         raise ValidationError('出版社名和地址不能一样')
    return attrs

# 视图类中:

from .serializer import PublishSerializer

Class PublishView(APIView):
    def get(self,request):
        publish_list = Publish.objects.all()
        ser = PublishSerializer(instance=publish_list, many=True)  # 如果序列化多条,要many=True
        return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data})

    def post(self,request):
        ser = PublishSerializer(data=request.data)  # 把待校验数据传入
        if ser.is_valid():     # 做数据校验---》三层
            print(ser.data)
        else:
            print(ser.errors)  # 没有校验通过,打印错误信息

序列化类保存

# 保存

1、在序列化类中,保存必须重写 create,完成真正的保存

def create(self, validated_data):
     # validated_data 校验过后的数据---》多传的数据,在这没有
     publish = Publish.objects.create(**validated_data)
     return publish  # 不要忘了返回新增的对象---》后续会拿着这个对象做序列化  ser.data--->根据它做序列化的

2、在视图类中,数据校验通过后,调用ser.save()
       
# 修改功能,也要校验和保存

1 在序列化类中,必须重写 update,完成真正的修改
def update(self, instance, validated_data):  # {name:上海出版社,add:上海地址}
     instance.name=validated_data.get('name')
     instance.addr=validated_data.get('addr')
     instance.save() # publish 对象的save---》保存到数据中
     return instance

2 视图类中
ser = PublishSerializer(instance=publish, data=request.data)
ser.save() # 虽然新增或修改都是调用save,但是内部做了判断

今日思维导图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1324279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

青少年CTF-qsnctf-Web-PingMe02

题目环境&#xff1a; 题目难度&#xff1a;★ 题目描述&#xff1a;诶&#xff1f;又是一道Ping题目诶&#xff01; 给了一个ip参数 传参&#xff1a; ?ip1.1.1.1 有回显结果 使用英文分号";"进行连接后续命令 列出此路径下的目录和文件 ?ip1.1.1.1;ls 列出根目录…

vue3表格导入导出.xlsx

在这次使用时恰好整出来了&#xff0c;希望大家也能学习到&#xff0c;特此分享出来 使用前确保安装以下模块&#xff0c;最好全局配置element-plus ### 展示一下 ### ###导出选项 ### ###导入de数据 ### 安装的模块 npm install js-table2excel // 安装js-table2excel n…

链表相关题目(数据结构期末复习)

题目要求 下面算法 FB1 将一个带头节点的单链表LA 分解为两个具有相同结构的单链表 LB&#xff0c;LC&#xff0c; 其中LB中节点为LA中值小于0的节点&#xff0c;而LC中节点为LA中值大于或等于0的节点。请在空白处填上合理的语句。 翻译&#xff1a;LA 初始链表&#xff1b;L…

Python图像文字识别详解,实战代码

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在现代计算机视觉和图像处理应用中&#xff0c;文字识别是一个重要的任务。本篇博客将详细介绍如何使用Python中的文字识别库&#xff0c;以及一些优秀的开源工具&#xff0c;来实现对图片中文字的准确识别。通过…

从学到考,一图带你读懂开发者技能成长秘籍

亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术&#xff0c;观点&#xff0c;和项目&#xff0c;并将中国优秀开发者或技术推荐给全球云社区。如果你还没有关注/收藏…

【Spring学习笔记】Spring 注解开发

Spring学习——注解开发 注解开发注解开发定义bean纯注解开发 Bean管理bean作用范围bean生命周期 依赖注入自动装配 第三方bean管理注解开发总结XML配置与注解配置比较 注解开发 注解开发定义bean 使用Component定义开发 Component("bookDao") public class BookD…

【Python可视化系列】一文教会你绘制美观的直方图(理论+源码)

一、引言 前面我详细介绍了如何绘制漂亮的折线图和柱状图&#xff1a; 【Python可视化系列】一文彻底教会你绘制美观的折线图&#xff08;理论源码&#xff09; 【Python可视化系列】一文教会你绘制美观的柱状图&#xff08;理论源码&#xff09; 对于一个连续性的变量&#xf…

spring三级缓存之相互依赖

spring三级缓存之相互依赖 什么是sping的互相依赖sping的三级缓存三级缓存存储了什么内容&#xff1f;三级缓存的存在是为了解决什么问题&#xff1f;三级缓存的怎样解决互相依赖的问题&#xff1f;缓存解决A和B相互依赖的过程三级缓存解决AOP并且A和B互相依赖的过程 三级缓存所…

Python 操作mysql实现事务处理

一、应用场景 Python项目对MySQL数据库进行增、删、改操作时&#xff0c;有时会出现执行sql异常的情况。在批量提交数据的时候&#xff0c;如果其中一个事务提交错误&#xff0c;往往导致预期的整个数据链不完整。 例如银行转账数据&#xff0c;用户A向用户B转账&#xff1a; …

blast安装及简单使用

一、安装blast 1.Ubuntu环境 # 下载blast wget https://ftp.ncbi.nlm.nih.gov/blast/executables/blast/2.9.0/ncbi-blast-2.9.0-x64-linux.tar.gz # 解压blast压缩包 tar -xzvf ncbi-blast-2.9.0-x64-linux.tar.gz # 测试 ./bin/blastp -h 这里就代表安装成功了&#xff0c;…

Mac电脑上设置一位数密码

1. 打开“终端”应用程序&#xff0c;你可以在 “ 应用程序 ” 文件夹中找到它。 2. 在终端窗口中&#xff0c;输入以下命令并按下回车键 pwpolicy -clearaccountpolicies 这个命令的目的是清除全局账户策略&#xff0c;允许设置较低位数的密码。 3. 输入你的开机密码并按下…

springCould-从小白开始【1】

目录 1.说明 2.父工程 3.服务端 4.消费者 5.公共模块 6.RestTemplate 1.说明❤️❤️❤️ 创建三个模块&#xff0c;服务者&#xff0c;消费者&#xff0c;公共api 注&#xff1a;spring boot和spring cloud有版本约束 2.父工程 ❤️❤️❤️ 约定版本号配置 注意&…

GSCoolink GSV1201E Type C/DP1.2转HDM1.4

DisplayPort 1.2 to HDMI 1.4 Converter with Embedded MCU 功能特征 1、GSV1201E是一款高性能、低功耗、USB Type-C Alternate Mode DisplayPort 1.2 to HDMI 1.4转换器。 2、显示接口接收器支持21.6Gbps(HBR2&#xff0c;4-lane)。 3、HDMI发射器支持9Gbps(TMDS3G3Lane)。…

OpenHarmony南向之TP触摸屏

概述 Touchscreen驱动用于驱动触摸屏使其正常工作&#xff0c;该驱动主要完成如下工作&#xff1a;对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口&#xff08;I2C或SPI&#xff09;、设定Input相关配置、下载及更新固件等操作。 Touchscreen驱…

mysql:查看线程缓存中的线程数量

使用命令show global status like Threads_cached;可以查看线程缓存中的线程数量。 例如&#xff0c;查询线程缓存中的线程数量如下&#xff1a; 然后启动应用程序&#xff0c;使用连接&#xff0c;查询如下&#xff1a; 由查询结果可以看到&#xff0c;线程缓存中的线程数量…

人工智能时代,看好硅光子!

硅光子学是一种用于制备光子集成电路&#xff08;PIC&#xff09;的技术&#xff0c;通常用于产生、检测、传输和处理光。这种方法使用半导体绝缘体上硅&#xff08;SOI&#xff09;晶片作为衬底材料&#xff0c;并采用标准的互补金属氧化物半导体&#xff08;CMOS&#xff09;…

弧形导轨的类型及应用

弧形导轨又叫圆弧形导轨&#xff0c;滚轮弧形导轨&#xff0c;是通过V型滚轮在圆弧形V型导轨面上的滚动&#xff0c;实现圆周运动&#xff1b;在工业自动化中&#xff0c;有些应用需要弧线运动&#xff0c;或者两个相交或平行的直线运动&#xff0c;这些情况需要通过弧线运动连…

netsdk1004 找不到资产文件“d:\vs-code\consoleapp1\consoleapp1\obj\project.assets.json”

今天学C#遇到一个问题记录下 创建如上所示的项目后运行出错&#xff1a; netsdk1004 找不到资产文件“d:\vs-code\consoleapp1\consoleapp1\obj\project.assets.json”。运行 nuget 包还原以生成此文件。 consoleapp1 c:\program files\dotnet\sdk\8.0.100\sdks\microsoft.net…

pyCharm 创建一个FastApi web项目,实现接口调用

FastApi和Django区别 我这边演示项目使用的fastApi作为web框架&#xff0c;当然主流一般都是使用Django做web框架&#xff0c;但是Django是一个重量级web框架他有很多组件&#xff0c;如授权&#xff0c;分流等全套web功能。我这边呢只需要有个接口可以被别人调用&#xff0c;…

脉冲水表和光电直读水表有什么区别?

脉冲水表和光电直读水表是两种常见的水表类型&#xff0c;它们在原理和功能上有着一些明显的区别。在本文中&#xff0c;我们将探讨脉冲水表和光电直读水表的区别&#xff0c;并讨论它们各自的优势和适用场景。 首先&#xff0c;我们来看看脉冲水表。脉冲水表是一种机械式水表&…