首页 > 其他分享 >【Django-rest-framework框架】第02回 APIView与序列化

【Django-rest-framework框架】第02回 APIView与序列化

时间:2022-09-26 21:36:25浏览次数:65  
标签:02 APIView self request book 序列化 data

目录

1. Http协议

1.1 简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文本的传送协议。

HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

应用层:基于tcp/ip之上,用于网络传输,广泛应用前后端的交互

1.2 四大特性

1. 基于请求响应
2. 基于TCP/IP之上用于应用层的协议
3. 无状态
4. 无/短连接

1.3 请求数据格式

1. 请求首行: 请求方式get,post, 请求地址:get携带数据,请求协议版本:0.9/1.1/2.x
2. 请求头:key:value
   Cookie:这是最重要的请求头信息之一
   Accept:浏览器可接受的MIME类型。
   Host:初始URL中的主机和端口 
   From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。
   Date 当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。
3. 请求体:post请求携带数据:三种编码格式
   1. Content-Type:application/x-www-form-urlencoded  ajax默认的数据格式,请求体中的数据以json字符串的形式发送到后台
   2. Content-Type:application/json;charset=utf-8  axios默认的数据格式,请求中的数据会以普通表单形式发送到后端
   3. Content-Type:multipart/from-data  他会将请求体的数据处理为一条消息,以标签为单元,用分隔符分开,既可以上传键值对,也可以上传文件

1.4 响应数据格式

1. 响应首行:响应协议版本,状态码,状态描述字符串
   1XX: 信息性状态码,接收的请求正在处理
   2XX:成功状态码, 请求正常处理完毕
   3XX: 重定向状态码,需要进行附加操作以完成请求
   4XX: 客户端错误状态码, 服务器无法处理请求
   5XX: 服务器错误状态码, 服务器处理请求出错
2. 响应头:key:value
   Allow: 服务器支持哪些请求方法
   Content-Length: 响应体的字节长度
   Content-Type: 响应体的MIME类型
   Content-Encoding: 设置数据使用的编码类型
   Date: 设置消息发送的日期和时间
3. 响应体:浏览器里看到的东西
   服务端返回数据 html格式,json格式

1.5 http协议版本区别

1. HTTP 0.9是最初的HTTP协议
   每个http请求都是一个tcp的链接
   只支持GET请求
   没有协议头
   无状态性
   只能传输超文本
2. HTTP 1.0
   新增了POST和HEAD命令
   可以设置contentType传输多种数据格式
   新增状态码,权限,内容编码等
3. HTTP 1.1 目前最流行
   keep-alvie,多个http请求可以使用同一个tcp
   请求和响应都支持Host头域,认为每一个服务器都绑定唯一的一个IP地址。
4. HTTP 2.0 
   增加双工模式,提高利用率
   服务端推送:不经请求向客户端发送数据
   二进制分帧层
   头信息压缩机制

2. APIView基本使用

1. 什么是rest_framework
   它是基于Django的,帮助我们快速开发符合RESTful规范的接口框架。
   安装方式有很多种,可以通过pip,或者在pycharm中安装也可以
2. APIView
   drf:是一个第三方的app,只能在djagno上使用,安装了drf后,导入一个视图类APIView,所有后期要使用drf写视图类,都是继承APIView及其子类.
   它的作用和from django.views import View中的View作用差不多,APIView是继承了View,所以执行as_view,dispatch方法都会
先走到APIView这个类中。所以通过这个APIView里的dispatch进行一层封装,对request这个对象进行改变,添加了认证、权限、频率这些

2.1 获取图书接口使用View+JsonResponsexie

views

from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
from django.views import View
from .models import Book


class BookView(View):
    def get(self, request):
        print(type(request))
        book_list = Book.objects.all()
        # book_list 是queryset对象不能直接序列化,只能通过for循环一个个列表套字典的形式
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return JsonResponse(res_list, safe=False, json_dumps_params={'ensure_ascii': False})  # 只能序列化字典与列表

urls

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

2.2 使用APIView+drf的Response

views

# dir帮我们封装了请求类,响应类,路由类,视图类
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request


# APIView继承自django的View
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        res_list = []
        for book in book_list:
            res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return Response(res_list)

3. APIView源码分析

# 视图类继承APIView后,执行流程就发生了变化,这个变化就是整个drf的执行流程
# 一旦继承了APIView入口,路由配置跟之前继承View是一样的-->找到图类的as_view-->APIView的as_view

@classmethod
def as_view(cls, **initkwargs):
    # 又调用了父类(View)的as_view
    view = super().as_view(**initkwargs)

    # 注释意思是从此以后,所有的请求都没有csrf的校验了
    # all other authentication is CSRF exempt.

    # 去掉csrf,在函数上加装饰器
    # @csrf_exempt
    # def index(request):
    #    pass
    # 本质等同于 index=csrf_exemot(index)
    return csrf_exempt(view)

# 请求来了,路由匹配成功会执行 View类的as_view类方法内的view闭包函数(但是没有csrf认证)
# 真正的执行,执行self.dispatch-->APIView的dispatch
def dispatch(self, request, *args, **kwargs):
    # 参数的request是原本的django原生的request
    # 下面的request,变成了drf提供的Request类的对象-->return Request(...)
    request = self.initialize_request(request, *args, **kwargs)
    # self 是视图类的对象,视图类对象.request=request 新的request
    self.request = request
        try:
            # 执行了认证,频率,权限 [不读]
            self.initial(request, *args, **kwargs)
            # 原来的View的dispatch的东西
            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

3.1 总结

1. 只要继承APIView都没有csrf的认证了
2. 以后视图类中使用的request对象,已经变成了drf提供的Request类的对象了
3. 执行视图类的方法之前,执行了3大认证(认证,权限,频率)
4. 在执行三大认证和视图类的方法过程中只要报错,都会被捕获处理

3.2 验证APIView的使用

1. 视图类中使用的request对象,已经变成了drf提供的Request类的对象了

原生djiango 的request是这个类的对象:
<class 'django.core.handlers.wsgi.WSGIRequest'>

drf的request是这个类的对象:
<class 'rest_framework.request.Request'>
<class 'rest_framework.request.Request'>

2. request已经不是原来的request了,还能像原来的request一样使用吗?
用起来 像之前一样

print(request.method)  # get
print(request.path)  # /books/
print(request.GET)  # 原来的get请求提交的参数
print(request.POST)  # 原来post请求提交的参数

4. Request的源码分析:rest_framework.request.Request

类中有个魔法方法:__getattr__    对象.属性,属性不存在会触发它的执行
def __getattr__(self, attr): # 如果取的属性不存在会去原生django的request对象中取出来
        try:
            #反射:根据字符串获取属性或方法,self._request 是原来的request
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)
        
以后用的所有属性或方法,直接用就可以了---》(通过反射去原来的request中取的)
新的request内部有个老的request,就是 request._request
data 是个方法,被property装饰了,变成了数据属性用
   以后body体中提交的数据,都从这里取(request.POST)
   urlencoded,form-data:提交的数据在request.POST中
   json格式提交的数据,在requets.POST中没有,它在request.body中
   现在无论那种格式,都从request.data中取
query_params:get请求提交的参数,等同于request._request.GET 或  request.GET
其他:取文件也是从request.FILES中取,跟之前一样

原生requets.POST 只有urlencoded和form-data格式提交的数据,json格式提交的数据在body中,拿出来自己处理,但是drf的request中有个data,data中可以取到任意编码提交的数据 
request.data  有时候是(urlencoded,form-data)QueryDict,有时候(json)是字典

4.1 什么是魔法方法

1 在类中只要以__开头,__结尾的都称之为魔法方法
2 这种方法不需要手动调用,某种情况会自动触发
3 eg: __init__,__str__,__call__,......

5. 序列化

5.1 序列化组件介绍

是什么?drf提供的一个类,我们继承它,写自己的类
有什么用?就是用来序列化qs或单个对象的
获取所有图书接口--> qs,单个book对象转成json格式字符串,给前端--> 序列化,使用for循环,列表套字典拼接的
drf提供了一种可以快速实现序列化的类:序列化类

1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能

5.2 序列化组件基本使用

5.2.1 定义一个序列化类

serializer

# 写序列化类,给book进行序列化
# from rest_framework.serializers import Serializer
from rest_framework import serializers


class BookSerializer(serializers.Serializer):
    # 要序列化的字段,有很多字段类,字段类有很多字段属性
    # 写几个字段就序列化几个字段
    name = serializers.CharField()  # 字段类
    price = serializers.CharField()  # 字段类
    publish = serializers.CharField()  # 字段类

5.2.2 使用序列化类,序列化多条数据

views

# 写序列化类:给book进行序列化
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from .serializer import BookSerializer

class BookView(APIView):  # APIView继承自django的view
    def get(self,request):
        book_list = Book.objects.all()
        # instance表示要序列化的数据,mang=True表示序列化多条(instance是qs对象,一定要传many=True)
        ser = BookSerializer(instance=book_list, many=True)

        return Response(ser.data)

5.2.3 使用序列化类,序列化单挑数据

class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

path('books/<int:pk>/', BookDetailView.as_view()),

5.3 反序列化

5.3.1 新增视图类

class BookView(APIView):  # APIView继承自django的View
    def post(self, request):
        # 前端传递数据,从request.data取出来
        ser = BookSerializer(data=request.data)
        if ser.is_valid():  # 表示校验前端传入的数据   没有写校验规则,现在等于没校验
            ser.save()  # 再写东西,这里会报错  调用save会触发BookSerializer的save方法,判断了,如果instance有值执行update,没有值执行create
            return Response(ser.data)
        else:
            return Response(ser.errors)

序列化类

# 写序列化类,给book进行序列化
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.Serializer):
    # 要序列化的字段,有很多字段类,字段类有很多字段属性
    # 写几个字段就序列化几个字段
    name = serializers.CharField()  # 字段类
    price = serializers.CharField()  # 字段类
    publish = serializers.CharField()  # 字段类

    # 重写create方法
    def create(self, validated_data):
        res = Book.objects.create(**validated_data)
        return res

5.3.2 修改视图类

class BookDetailView(APIView):
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

序列化类

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.Serializer):
    # 要序列化的字段,有很多字段类,字段类有很多字段属性
    # 写几个字段就序列化几个字段
    name = serializers.CharField()  # 字段类
    price = serializers.CharField()  # 字段类
    publish = serializers.CharField()  # 字段类

    # 重写update方法
    def update(self, instance, validated_data):
        # instance要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance

5.3.3 删除

class BookDetailView(APIView):
    def delete(self, instance, pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

标签:02,APIView,self,request,book,序列化,data
From: https://www.cnblogs.com/cainiaozhy/p/16732563.html

相关文章

  • luogu P2233 [HNOI2002]公交车路线
    [HNOI2002]公交车路线题目描述在长沙城新建的环城公路上一共有\(8\)个公交站,分别为A、B、C、D、E、F、G、H。公共汽车只能够在相邻的两个公交站之间运行,因此你从某一......
  • JavaWeb--Mybatis--2022年9月25日
    第一节  Mybatis概述1.Mybatis概念tips:持久层是什么:负责将数据保存到数据库的那一层代码,以后开发我们会将操作数据库的......
  • APIView源码解析 和 Request类源码解析
    APIView源码解析入口也是as_view()apiview的as_view里面调用了一个super()方法调用父类的as_view返回了一个csrf_exempt(viwe)#备注:所有的请求没有csrf的校验了在......
  • 42ed 2022/9/10&2021/9/17 纪中CSP.S组第一轮训练
    第一次(2022/9/10:陕西2020)得分70,不高不低,略有不足,因为还有一些题目的分能拿但没拿到,考试共进行了2h,原本应该是4h,仍然都能做完,还进行了两次检查首先是在选择题上,一道栽在......
  • 41st 2022/9/2 CSP前思想准备
    面临虽说上次过了第一轮,但是仍然很慌因为上次只是第一次过了第一轮,虽然有些把握,但却不是百分百怎么说呢,我不太相信自己第二轮会多烂,但是如果烂在了第一轮,那就真的是哑巴......
  • 40th 2022/8/17 模拟赛总结29
    这次能接受,因为T1是唯一能简单拿分的,但是我对状压DP的这一类,反而是最板子的题目不熟悉状压DP,需复习并进行简单提升其实今天是看出来了是状压,但就是打不出来,一直算空间时......
  • P6835 [Cnoi2020]线形生物 题解
    通过这道题可以看出来pz根本不会期望考虑期望线性性质,设\(E_{x\toy}\)表示从\(x\)走到\(y\)的期望步数,那么有\(E_{1\ton+1}=\sum_{i=1}^nE_{i\toi+1}\),因此考......
  • 2022icpc网络赛 A题B题
    AYetAnotherRemainder费马小定理\(10^{p-1}\%p==1\)考虑第\(p-1\)行字符串为\(a_1a_2a_3a_4a_5a_6\)假设当前模数p为3那考虑第2行然后第一个数是\(a_1+a_3+a_......
  • 38th 2022/8/13 模拟赛总结27
    这次哈!前一天我就不该喝咖啡的!但后悔也来不及了!!!睡很晚,这次再次让我体会到了睡眠的重要性痛苦,比赛时有力没法使,就很好,甚至还去拉虚脱了因为既着凉,又没精神,直接崩溃然后......
  • 37th 2022/8/12 模拟赛总结26
    这次真不可理喻这次T1是差分约束,这次,得完全弄懂T1,因为之前考过差分约束,但一直都不会,改了题后却没有印象,这次做出总结:就是一个将输入改为一条形同松弛原理的式子,如:\(X_i-X......