序列化和反序列化

api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段:序列化、反序列化

序列化:把我们语言识别的数据转换成指定的格式提供给别人。

字典,列表,对象  --->  json/xml/prop,massagepack ---> 将json格式的数据提供给别人(前端或其他服务)

'''
序列化和反序列化的格式不仅仅用json格式。
json格式的可读性太高,安全性不足。可以采用prop、massagepack格式等。
'''

反序列化:把别人提供的数据转换/还原成我们需要的格式。


我们在django中获取到的数据默认是模型对象(qreryset对象),但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人,这个转换过程称为 ---> '序列化过程' 前端传入到后台的数据 ---> json格式字符串 ---> 后端将数据存到数据库中,需要将数据转成python中的对象 ---> 把json格式字符串转成python对象存到数据库的过程称为 ---> '反序列化'

drf介绍和安装

使用原生django写接口

原生django,不使用任何其他模块,也可以写出符合resful规范的接口,就是写起来麻烦一些。

# 查询所有图书
地址:127.0.0.1:8080/books
路由:path('/books',views.books)
视图函数中:
1. 通过orm查出所有图书对象(qreryset)
2. 序列化(for循环取出数据自己拼成列表套字典):
[{name:西游记,price:99},{name:红楼梦,price:99}]
3. JsonResponse返回给前端

django DRF安装

# 定义
drf是django的一个app。 # 作用
帮助程序员快速在django上写符合restful规范的接口 # 安装:
pip install djangorestframework # 安装的注意事项:
1.django的最新版本当前为 4.x , 一般我们将django升级到 3.x 或者 2.x
2.drf的最新版本最低支持django 2.2及以上;
'''
如果你的版本低于2.2:
当你安装最新版drf的时候, 会把你老版本的django卸载,给你装上最新版,导致原来的django项目出现问题,运行不了
''' # 建议:
django 2.2 以下版本 ---> 使用低版本的drf
django 3.x ---> 使用最新版本的drf

drf快速使用

# 针对于一个表,通常需要写哪些接口?
通常需要写5个接口,以后看到的所有接口都是这5个接口的变形。 # 五个基本接口:
'需求名' '请求方式' '访问的路由'
-查询所有 ---> get -> http://127.0.0.1:8000/books/
-查询一个 ---> get -> http://127.0.0.1:8000/books/1/
-新增一个 ---> post -> http://127.0.0.1:8000/books/
请求体body中携带新增的数据 -修改 ---> put,patch
(实际编码中,基本都用put)
-> http://127.0.0.1:8000/books/1/
请求体body中传入修改的数据 -删除一个 ---> delete -> http://127.0.0.1:8000/books/1/ # 注册、登录接口的本质:
登陆接口 ---> 本质其实是查询一个
注册接口 ---> 本质是新增一个 # postman测试接口的特点:
postman的接口测试是严格的,对于一个路由地址,斜杠有和没有是有区别的。
postman不会像浏览器一样,自动补全斜杠再请求一次。

模型

在模型层创建一个简单的只有3个字段的图书类。

class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(decimal_places=2, max_digits=5)
author = models.CharField(max_length=32)

序列化类

新建一个py文件编写序列化类BookSerializer。

from .models import Book
from rest_framework import serializers class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'

视图

在视图层使用相对导入,导入刚刚创建的图书类。(也可以使用绝对导入,但是推荐使用相对导入)

导入ModelViewSet模块,自己写一个类继承这个模块。

类中属性serializer_class使用我们刚刚创建的序列化类。

from rest_framework.viewsets import ModelViewSet
from .models import Book # 模块导入推荐使用相对导入
# from app01.models import Book # 使用绝对导入
from .serializer import BookSerializer
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer

路由

from rest_framework.routers import SimpleRouter
from app01 import views router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls

datagrip

pycharm是java写的 django链接数据库需要java链接数据库的驱动

类似navicat。datagrip是pycharm公司写的链接数据的软件。

使用postman测试接口

使用get请求获取所有图书:

使用put请求修改图书:

使用patch请求修改图书:

可以只局部修改一部分。

CBV源码分析

1. cbv路由写法:
path('test/', views.TestView.as_view())
2. path的第二个参数实际是函数内存地址
3. as_view()执行完,实际是闭包函数view的内存地址
4. 当请求来了,路由匹配成功,会执行view(request),传入当次请求的request对象
5. view函数的返回值:return self.dispatch(request, *args, **kwargs)
6. View类中找dispatch
7. 如果是get请求就会执行视图类中的get方法,如果是post请求,就会执行视图类的post方法 # as_view 类的绑定方法--->View类的方法-->@classonlymethod
# dispatch核心代码--->getattr反射--->从当前对象(视图类的对象)--->如果是get请求-->会拿到get方法--->handler就是get方法--->handler(request)本质就是--->get(request)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
return handler(request, *args, **kwargs) # 通过描述符自己写装饰器来装饰类---》完成类似于property,classmethod。

查看源码推荐pycharm配置:

打开这个show Members,可以查看py文件里面的变量名。

classonlymethod:

classonlymethod继承于classmethod.

相当于django开发人员自定义的classmethod。

推荐阅读:

https://liuqingzheng.top/python/面向对象高阶/5-描述符(get%E5%92%8C__set__%E5%92%8C__delete__)/

drf之APIView分析

View类的导入方式

以后使用drf写接口,在视图层都是写视图类

drf最顶层的视图类是APIView,是drf中所有视图类的父类。

APIView又继承了django中的View类:

这个View是这样导入的:

from django.view.genenic import View

不对呀,我们之前写视图类,是这样导入的:

from django import view

然后我们的类继承 view.View

为什么这两种方式都会导入同一个View类?

不论是genenic还是view都是包名。

在包内的__init__文件注册View类就可以实现导入了。

# View类真实路径
from django.views.generic.base import View
# 因为在generic包的init里注册了
from django.views.generic import View
# 因为在views包的init里注册了
from django.views import View

继承了django View类的类,就是视图类。

所以继承APIView的类,也是视图类。

路由层写法和以前一样:

这里如果路由冲突了,会怎么样?(有两个视图类对应test/路由)

这里底层是for循环,将列表中的路由一个一个取出匹配,如果上面的匹配成功,for循环就break退出,不会继续匹配,所以下面这个视图类永远都不会执行。

APIView的执行流程

# APIView的执行流程
路由 path('order/', views.OrderView.as_view())---》第二个参数是函数内存地址---》APIView的as_view的执行结果---》本质还是用了View类的as_view内的view闭包函数,去掉了csrf认证----》当请求来了---》触发view闭包函数执行,并且传入request--->调用了self.dispatch-->self是视图类的对象,从OrderView中找dispatch,但是找不到----》父类APIView中有---》本质执行是APIView的dispatch----》

APIView的as_view方法

# APIView的as_view方法
view = super().as_view(**initkwargs) # 调用APIView的父类(View)的as_view方法
return csrf_exempt(view) # 去掉csrf_exempt的认证,以后只要继承了APIView后,csrf就无效了,无论中间件是否注释掉 # crsf的局部禁用--》在视图函数上加装饰器---》csrf_exempt装饰器---》装饰器本质就是一个函数
@csrf_exempt # 装饰器的@ 是一个语法糖(特殊语法)-->把下面的函数当参数传入装饰器中并且把返回结果赋值给函数名:index=csrf_exempt(index)
def index(request)
pass
跟 csrf_exempt(index) 一毛一样

路由 path('order/', views.OrderView.as_view()):

path第二个参数是函数内存地址:

我们自己的视图类OrderView里面没有as_view方法,所以回去父类APIView找as_view方法,

由于APIView里面有as_view,所以不会去APIView的父类View找。

APIView里的as_view:

重要的两行代码:

view = super().as_view(**initkwargs) # 调用APIView的父类(View)的as_view方法

return csrf_exempt(view) # 去掉csrf_exempt的认证,以后只要继承了APIView后,csrf就无效了,无论中间件是否注释掉

父类(View)的as_view方法最终会拿到 ---> 我们自己编写的视图类中的方法 :



如果来了一个get请求 dispatch方法会通过反射从我们视图类产生的对象中获取方法:

如何理解这行代码return csrf_exempt(view)

@csrf_exempt
def index(request):
pass
跟 csrf_exempt(index) 一模一样 # 因为装饰器的本质是:
index = csrf_exempt(index)

CBV本质上就是FBV。

发送请求到后端实际上就是执行了我们视图类中的一个函数。

如果视图层有一个视图函数:

def index(request):
return Httpresponse('你好')

正常情况下,我们给FBV添加装饰器语法糖实际上是执行了:index = csrf_exempt(index)

@csrf_exempt
def index(request):
return Httpresponse('你好')

当路由匹配成功时,看起来是执行index函数,实际是执行crsf_exempt(index)

FBV路由层看起来是这样子:

path('index/', views.index)

实际是:

path('index/', csrf_exempt(index))

CBV路由层看起来是这样子:

path('index/', views.TestView.as_view())

实际是:

path('index/', crsf_exempt(View))

这个View最终是我们视图类中的一个方法的函数地址(通过反射拿到的)

总结:APIView的as_view的作用只是给你自己写的视图类加了个crsf_exempt装饰器(去掉了crsf认证)

APIView的dispatch方法

# APIView的dispatch
def dispatch(self, request, *args, **kwargs):
# request是新的drf提供的request,它是由老的django的request得到的
# 通过老request,生成一个新request,drf的Request的对象
request = self.initialize_request(request, *args, **kwargs)
# 把新的request,放到了我们自己的视图类对象中
self.request = request
try:
# 执行了三大认证(认证,权限,频率)
self.initial(request, *args, **kwargs)
# self.http_method_names是个列表
if request.method.lower() in self.http_method_names:
# 原来dispatch的核心代码
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed) # 通过反射获取我们视图类中的方法
else:
handler = self.http_method_not_allowed
# 这里也是原来dispatch写的代码,但是request已经不是老request了,是上面生成的新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 # dispatch方法总结
请求来了之后,dispatch方法,先处理request产生新的request对象,将这个新的request对象放入我们自己视图类产生的对象中。
再进行三大认证,认证完了之后获取我们类中的方法并执行,最后dispatch方法返回一个返回值。 # APIView执行流程
1 包装了新的Request对象,以后视图类中的方法中传入的request对象都是新的
2 在进入视图函数之前,执行了三大认证
3 无论三大认证还是视图函数的方法,执行过程中出了异常,都会被处理掉

把新的request,放到了我们自己的视图类对象中:

http_method_names列表:

列表里面放了八大请求方法。

drf之Request对象分析

如何包装的新的request

initialize_request方法如何将django产生的老request包装成新的request?

#  如何包装的新的request
request = self.initialize_request(request, *args, **kwargs)---》由于我们的对象里没有initialize_request方法,所以去APIView找initialize_request方法---》核心代码 # initialize_request方法核心代码
from rest_framework.request import Request # 导入drf新Request类
return Request(
request, # 老的request
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
新的Request类中的__init__方法有如下代码:
self._request = request ---》新的request._request是老的request 新的:<class 'rest_framework.request.Request'>
老的:<class 'django.core.handlers.wsgi.WSGIRequest'>

APIView中的initialize_request方法:

drf 新Request类:

Request类__init__:

在我们写的视图类中查看老的request:

执行get方法里面的代码之前,我们的request已经被换成了新的request。get函数里面的request是drf产生的新request。

更多示例:

request._requestself.request._request存放的都是django产生的老request。

查看request的类型:

三大认证执行顺序

# 三大认证是如何走的
self.initial(request, *args, **kwargs)---》APIView的
核心代码:
self.perform_authentication(request) # 认证
self.check_permissions(request) #权限
self.check_throttles(request) # 频率 # 三大认证执行顺序
认证 ---> 权限 ---> 频率 # 总结
'''
路由匹配成功 ---三大认证---> 执行视图类中方法 三大认证有点类似于中间件: 请求到达后端服务器 ---中间件---> 路由匹配
'''

新Request常用属性和方法

request.data

# rest_framework.request.Request --->常用属性和方法

#  request.data定义
新的request有一个data方法(此方法被伪装成属性),前端post请求传入的数据都在equest.data里面。 # 与老的request.POST的区别
request.POST:
只能处理urlencoded和formdata编码格式。
request.data:
无论前端用什么编码格式的post提交的数据,都可以从request.data中获取。

未改变的方法

新的request也有一些方法和老request使用方式相同:


request.files # 新的request.files也是获取上传的文件对象 以后直接使用新的request.method request.path 拿到的就是老的request.method... # 跟之前用法相同

使用getattr调用老的request的方法

如何使用新request调用老request中的方法:

# 原理
对象.调用属性或方法会触发 魔法方法 __getattr__
原因在于新的request类重写了__getattr__,以后新的request.method用的时候本质就是request._request.method # 代码
1.使用新的request方法 ---> 执行request.method 2.当新request类中没有method这个名字时,触发新request类中的__getattr__方法 def __getattr__(self, attr): # 传入字符串'method'
try:
return getattr(self._request, attr) # 通过反射去老的里面取 self._request存的是老的request
except AttributeError:
return self.__getattribute__(attr) 3. 新的request.method用的时候本质就是:
request._request.method # 总结:新的request当老的用即可,只是多了个data属性,存放前端post请求传入的数据,三种编码格式都可以存放在data中。

新的request.data和老的request.POST的区别:

发送formdata编码格式:

发送json编码格式:

练习

1 APIView和Request源码部分
2 原来的django的request对象中没有data,写个装饰器,装在视图函数上(中间件),使得request.data-->无论什么编码格式,post提交数据,data都有值 def before(func):
def inner(request,*args,**kwargs):
request.data=request.POST res=func(request,*args,**kwargs)
return res
return inner @before
def test(request):
print(request.data)
return HttpResponse('ok')

drf快速使用 CBV源码分析 drf之APIView分析 drf之Request对象分析的更多相关文章

  1. Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析

    一.一个请求来到Django 的生命周期   FBV 不讨论 CBV: 请求被代理转发到uwsgi: 开始Django的流程: 首先经过中间件process_request (session等) 然后 ...

  2. 序列化与反序列化、def的介绍与快速使用、cbv源码分析、APIView与request对象分析

    今日内容概要 序列化与反序列化 def介绍和快速使用 cbv源码流程分析 drf之APIView和Request对象分析 内容详细 1.序列化和反序列化 # api接口开发 最核心最常见的一个过程就是 ...

  3. Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)

    一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...

  4. drf的基本使用、APIView源码分析和CBV源码拓展

    cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...

  5. Django drf:cbv源码、resful规范及接口、drf使用、response源码、序列化

    一.cbv源码分析 二.resful规范 三.django中写resful的借口 四.drf写resful的借口 五.APIVIew源码分析 六.drf之序列化 一.cbv源码分析 -CBV和FBV ...

  6. drf 简介以及部分源码分析

    目录 复习 drf框架 全称:django-rest framework 知识点 接口 restful接口规范 基于restful规范的原生Django接口 主路由:url.py api组件的子路由: ...

  7. CBV源码分析+APIVIew源码分析

    {drf,resful,apiview,序列化组件,视图组件,认证组件,权限组件,频率组件,解析器,分页器,响应器,URL控制器,版本控制} 一.CBV源码分析准备工作: 新建一个Django项目 写 ...

  8. Django框架(十七)-- CBV源码分析、restful规范、restframework框架

    一.CBV源码分析 1.url层的使用CBV from app01 import views url(r'book/',views.Book.as_view) 2.as_view方法 as_view是 ...

  9. Django框架(十八)—— CBV源码分析、restful规范、restframework框架

    目录 CBV源码分析.restful规范.restframework框架 一.CBV源码分析 1.url层的使用CBV 2.as_view方法 3.view方法 4.dispatch方法(可以在视图层 ...

  10. 15.DRF学习以及相关源码阅读

    1.http请求协议 代码很枯燥,结果和奇妙. 1.cbv django.vuews import View classs LoginView(View): def get(self,requset) ...

随机推荐

  1. 洛谷P2367 语文成绩(差分)

    标准的差分应用题,不要想的太复杂,写成了线段树. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5e6+10 ...

  2. Mapper 实体转换Entiy to Dto

    实际使用中发现很多问题 如果用EFcore 框架,这个表达式树生成一个新的实体导致EFcore 跟踪失败!/// <summary> /// 生成表达式目录树 泛型缓存 /// </ ...

  3. 方法的重写(override / overwrite)

    1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作 2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法. 重写的规 ...

  4. springboot+thymeleaf+bootstrap 超级无敌简洁的页面展示 商城管理页面

    页面效果: <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org&quo ...

  5. 14.-F对象和Q对象

    一.F对象 一个F对象代表数据库中某条记录的字段的信息 作用 通常是对数据库中的字段值在不获取的情况下进行操作 用于属性(字段)之间的比较   语法: from django.db.models im ...

  6. C++智能指针的enable_shared_from_this和shared_from_this机制

    前言 之前学习muduo网络库的时候,看到作者陈硕用到了enable_shared_from_this和shared_from_this,一直对此概念是一个模糊的认识,隐约记着这个机制是在计数器智能指 ...

  7. clang在编译时指定目标文件所需的最低macOS版本

    调研这个的原因,是因为有个同事在macOS 12.2上打包好的程序,放在macOS 10.15上运行时报错: Dyld Error Message:  Symbol not found: __ZNKS ...

  8. 云实例初始化工具cloud-init简介

    项目简介 cloud-init是一款用于初始化云服务器的工具,它拥有丰富的模块,能够为云服务器提供的能力有:初始化密码.扩容根分区.设置主机名.注入公钥.执行自定义脚本等等,功能十分强大. 目前为止c ...

  9. linux下进程的实际用户ID(有效组)和有效用户ID(有效组ID)

    实际用户ID(实际组ID):标识当前用户(所属组)是谁,当用户登陆时取自口令文件. 有效用户ID(有效组ID):用来决定我们(当前进程)对文件的访问权(即实际该进程的是以那个用户运行的). 一般情况下 ...

  10. C ++:树

    C++:树 树的概念: 所谓"树"是输就结构的一种,树大概可以分为两大类: 有根树 和 无根树 有根树使有一个确定的根节点,反之为无根树 · 子节点:从树根开始,通过树边向下扩展的 ...