今日内容概要
- 序列化与反序列化
- 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.xdrf的最新版本最低支持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 最新版为例
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 请求:只修改某个字段--->实际编码中,基本都用puthttp://127.0.0.1:8000/books/1/ body体中传入修改的数据-删除一个---》delete-->http://127.0.0.1:8000/books/1/# 登陆接口---》本质其实是查询一个# 注册接口----》本质是新增一个# postman测试,地址要严格,斜杠有和没有是有区别的
视图 views.py
# 写5个接口---》配5个视图函数# 使用drf来写-->使用视图类from rest_framework.viewsets import ModelViewSetfrom .models import Book # 模块导入使用相对导入# from app01.models import Book # 使用绝对导入from .serializer import BookSerializerclass BookView(ModelViewSet):queryset = Book.objects.all()serializer_class = BookSerializer
路由 urls.py
from django.contrib import adminfrom django.urls import pathfrom rest_framework.routers import SimpleRouterfrom app01 import viewsrouter = SimpleRouter()router.register(\'books\', views.BookView, \'books\')urlpatterns = [path(\'admin/\', admin.site.urls),]urlpatterns += router.urls
序列化类 在app01下创建serializer.py文件
from .models import Bookfrom rest_framework import serializersclass BookSerializer(serializers.ModelSerializer):class Meta:model = Bookfields = \'__all__\'
模型 models.py
from django.db import modelsclass 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的dispatchdef dispatch(self, request, *args, **kwargs):# request是新的drf提供的request,它是由老的django的request得到的# 通过老request,生成一个新request,drf的Request的对象request = self.initialize_request(request, *args, **kwargs)# 把新的request,放到了视图类对象中self.request = requesttry:# 执行了三大认证(认证,权限,频率)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 无论三大认证还是视图函数的方法,执行过程中出了异常,都会被处理掉# 如何包装的新的requestrequest = self.initialize_request(request, *args, **kwargs)APIView的initialize_request 核心代码:from rest_framework.request import Requestreturn Request(request, # 老的requestparsers=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.methoddef __getattr__(self, attr):try:return getattr(self._request, attr) # 通过反射去老的里面取except AttributeError:return self.__getattribute__(attr)# 总结:新的request当老的用即可,只是多了个data前端post请求传入的数据,三种编码格式都可以