首页 > 技术文章 > 序列化与反序列化、def的介绍与快速使用、cbv源码分析、APIView与request对象分析

jgx0 2022-03-29 22:16 原文

今日内容概要

  • 序列化与反序列化
  • def介绍和快速使用
  • cbv源码流程分析
  • drf之APIView和Request对象分析

内容详细

1、序列化和反序列化

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

	# 序列化:把我们语言识别的数据转换成指定的格式提供给别人:
		字典,列表,对象------》json/xml/prop,massagepack--->提供给别人(前端或其他服务)

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


我们在django中获取到的数据默认是模型对象(qs对象),但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人----》序列化过程

前端传入到后台的数据---》json格式字符串---》后端存到数据库中,需要转成python中的对象---》把json格式字符串转成python对象存到数据库的过程称为----》反序列化

2、drf介绍和快速使用

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

# 以查询所有图书为例:
	地址:127.0.0.1:8080/books
	路由:path('/books',views.books)  # django 2.x
	视图函数中:通过orm查出所有图书(qs)--->序列化(for循环自己拼成列表套字典[{name:西游记,price:99},{name:红楼梦,price:99}])---->JsonResponse返回给前端
    
# drf是django的一个app--》帮助咱们快速在django上写符合restful规范的接口

# 安装:
	pip3 install djangorestframework
    
	注意:django版本最新 4.x     一般用升级到3.x 或者 2.x
	drf的最新版本最低支持django 3.x以上---》出一个小问题---》装django 2.x---》当你pip3 install的时候,由于低于2.2不支持最新的drf---》把你老版本的django卸载---》给你装上最新版---》原来写的django项目可能有问题,运行不了
  
	django2.2以下--->drf降版本
	django3.x---->drf使用最新
# 官方说明版本问题:
	Python (3.6, 3.7, 3.8, 3.9, 3.10)
	Django (2.2, 3.0, 3.1, 3.2, 4.0)

# 此后演示 以django 2.2 djangorestframework 最新版为例

image

2.1、快速使用

# 针对于一个表,需要写那些接口---》5个
	以后看到的所有接口都是这5个的变形:
	使用postman测试:
		-查询所有---》get 请求->http://127.0.0.1:8000/books/
		-查询一个---》get 请求->http://127.0.0.1:8000/books/2/
		-新增一个---》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测试,地址要严格,斜杠有和没有是有区别的        

image

image

视图 views.py

# 写5个接口---》配5个视图函数
# 使用drf来写-->使用视图类
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

路由 urls.py

from django.contrib import admin
from django.urls import path

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

序列化类 在app01下创建serializer.py文件

from .models import Book
from rest_framework import serializers


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

模型 models.py

from django.db import models


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)

3、cbv源码流程分析

# cbv路由写法:
	path('test/', views.TestView.as_view())
"""
第二个参数是函数内存地址 views.TestView.as_view()

as_view()执行完,也是一个内存地址>>>闭包函数view的内存地址
	当请求来了,路由匹配成功
	执行view(request) 传入当次请求的request对象

执行view(request) 本质上就是:
	return self.dispatch(request, *args, **kwargs)
	去View类中找 dispatch
		如果是get请求就会执行视图类中的get方法
		如果是post请求,就会执行视图类的post方法
"""
	

# as_view 是类的绑定方法
	View类的方法--》@classonlymethod
    
# dispatch核心代码
	handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    
	return handler(request, *args, **kwargs)
"""
getattr反射
	从当前对象(视图类的对象)---》如果是get请求--》会拿到get方法
	
handler就是get方法
	handler(request)本质就是---》get(request)
"""

# 可以通过描述符自己写装饰器来装饰类(了解)
	完成类似于property,classmethod...

4、drf之APIView和Request对象分析

from django.views.generic.base import View  # 按照最真实的路径导入

from django.views.generic import View  # 因为在generic包的init里注册了

from django.views import View  # views包的init里注册了 generic.base


# APIView的执行流程
路由:path('order/', views.OrderView.as_view())

	第二个参数是函数内存地址
    
	APIView的as_view的执行结果:
		本质还是用了View类的as_view内的view闭包函数,去掉了csrf认证
        
	当请求来了 触发view闭包函数执行,并且传入request 调用了 self.dispatch:
		self是视图类的对象,从OrderView中找dispatch,但是找不到 父类APIView中有 本质上执行的dispatch是APIView
    
    
# APIView的as_view方法
	view = super().as_view(**initkwargs)  # 调用 APIView的父类(View)的as_view方法
	return csrf_exempt(view)  # 去掉csrf_exempt的认证,以后只要继承了APIView后,csrf就无效了,无论中间件是否注释掉


# 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了,是新的
			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


      
# APIView执行流程概述
	1 包装了新的Request对象,以后视图类中的方法中传入的request对象都是新的
	2 在进入视图函数之前,执行了三大认证
	3 无论三大认证还是视图函数的方法,执行过程中出了异常,都会被处理掉
      
    
#  如何包装的新的request
request = self.initialize_request(request, *args, **kwargs)

APIView的initialize_request 核心代码:

from rest_framework.request import Request

return Request(
		request,  # 老的request
		parsers=self.get_parsers(),
		authenticators=self.get_authenticators(),
		negotiator=self.get_content_negotiator(),
		parser_context=parser_context
	)

	新的Request中:self._request = request
	新的request._request是老的request

	新的:<class 'rest_framework.request.Request'>
	老的:<class 'django.core.handlers.wsgi.WSGIRequest'>

# 三大认证是如何走的
	self.initial(request, *args, **kwargs)
	APIView的核心代码:
		self.perform_authentication(request)  # 认证
		self.check_permissions(request)  # 权限
		self.check_throttles(request)  # 频率
    
    
# 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) 一毛一样

Request对象分析

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

# request.data
	前端post请求传入的数据 在老的request.POST请求下 老的只能处理urlencoded和formdata编码格式,json格式不能处理
	无论前端用什么编码post提交的数据,都从data中获取
    
# request.files  # 上传的文件对象
	以后直接使用新的request.method  request.path 拿到的就是老的 request.method...
	对象.调用属性或方法会触发 魔法方法 __getattr__
	原因在于新的request类重写了__getattr__, 以后新的request.method用的时候本质就是request._request.method
	def __getattr__(self, attr):
		try:
			return getattr(self._request, attr)  # 通过反射去老的里面取
		except AttributeError:
			return self.__getattribute__(attr)

        
# 总结:
	新的request当老的用即可,只是多了个data前端post请求传入的数据,三种编码格式都可以

image

推荐阅读