drf学习-2
一、APIView基本使用
drf:只是django一个第三方app, 换别的web框架用不了
安装了drf之后,导入一个视图类APIView,所有后期要是用drf写视图类,实际上都是继承APIView及其子类
获取所有图书接口
1.创建个书籍表
2.使用View+JsonResponse写获取所有的图书接口
3.接口
使用APIView+Response写获取所有图书馆的接口
会直接报错,去settings配置'rest_framework'后就可以 页面也会变得美化
二、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的校验了
# 在函数上加装饰器
@csrf_exempt
def index(request):
pass
本质等同于 index=csrf_exempt(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
总结
- 只要继承APIView都没有csrf的认证
- 以后视图类中使用的request对象,已经变成了drf提供的Request类的对象了
- 执行视图类的方法之前,执行了3大认证(认证、权限、频率)
- 在执行3大认证和视图类的方法过程中只要报错,都会被捕获处理
三、Request类源码分析
#1 视图类中使用的request对象,已经变成了drf提供的Request类的对象了
-原生djagno 的request是这个类的对象:django.core.handlers.wsgi.WSGIRequest
-drf的request是这个类的对象:rest_framework.request.Request
#2 request已经不是原来的request了,还能像原来的request一样使用吗?
-用起来,像之前一样
print(request.method) # get
print(request.path) # /books/
print(request.GET) # 原来的get请求提交的参数
print(request.POST) # 原来post请求提交的参数
#3 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)是字典
番外篇-回顾知识点
什么是魔法方法?
魔法方法是指方法名以两个下划线开头并以两个下划线结尾的方法
魔法方法有哪些?
四、序列化组件介绍
什么是序列化组件?
drf提供的一个类,我们继承它,写自己的类
有什么作用?
用来序列化qs或单个对象的
获取所有图书接口----》qs,单个book对象转成json格式字符串,给前端---》序列化
-使用for循环,列表套字典拼接的
drf提供了一种可以快速实现序列化的类:序列化类
序列化组件基本使用
首先定义一个序列化类
# 写序列化类:给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()
使用序列化类,序列化 多条数据
class BookView(APIView): # APIView继承自django的View
def get(self, request):
book_list = Book.objects.all()
# instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
ser = BookSerializer(instance=book_list, many=True)
return Response(ser.data)
使用序列化类,序列化 单条数据
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
五、反序列化(新增、修改)
新增,修改---》前端传入的数据可能不合规,要校验---》序列化类有数据校验功能
新增
视图类
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)
序列化类
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
修改
视图类
class BookDetailView(APIView):
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
# 前端传递数据,从request.data取出来
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid(): # 表示校验前端传入的数据 没有写校验规则,现在等于没校验
ser.save() # 再写东西,这里会报错 调用save会触发BookSerializer的save方法,判断了,如果instance有值执行update,没有值执行create
return Response(ser.data)
else:
return Response(ser.errors)
序列化类
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
回顾小知识点
一、http协议版本区别 eg: 0.9 1.1 2.x?
http0.9特性
- 只有GET方法
- 使用ASCII字符流传输
http1.1特性
- 长连接:新增Connection字段,可以设置keep-alive值保持连接不断开; Host头字段,对虚拟主机的支持
- 管道化:基于上面长连接的基础,管道化可以不等第一个请求响应继续发送后面的请求,但响应的顺序还是按照请求的顺序返回
- 缓存处理:新增字段cache-control
- 断点传输
长连接:http1.1默认保持长连接,数据传输完成保持tcp连接不断开,继续用这个通道传输数据
管道化:基于长连接的基础,我们先看没有管道化请求响应:
tcp没有断开,用的同一个通道
请求1 > 响应1 --> 请求2 > 响应2 --> 请求3 > 响应3
管道化的请求响应:
请求1 --> 请求2 --> 请求3 > 响应1 --> 响应2 --> 响应3
即使服务器先准备好响应2,也是按照请求顺序先返回响应1
虽然管道化,可以一次发送多个请求,但是响应仍是顺序返回,仍然无法解决队头阻塞的问题
缓存处理:当浏览器请求资源时,先看是否有缓存的资源,如果有缓存,直接取,不会再发请求,如果没有缓存,则发送请求通过设置字段cache-control来控制
断点传输:在上传/下载资源时,如果资源过大,将其分割为多个部分,分别上传/下载,如果遇到网络故障,可以从已经上传/下载好的地方继续请求,不用从头开始,提高效率,在 Header 里两个参数实现的,客户端发请求时对应的是 Range 服务器端响应时对应的是 Content-Range
http2.0特性
- 二进制分帧
- 多路复用: 在共享TCP链接的基础上同时发送请求和响应
- 头部压缩 : HTTP 2.0会对HTTP的头进行一定的压缩,将原来每次都要携带的大量key value在两端建立一个索引表,对相同的头只发送索引表中的索引。
- 服务器推送:服务器可以额外的向客户端推送资源,而无需客户端明确的请求
二进制分帧:将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码。常见的帧有Header帧,用于传输Header内容,并且会开启个新的流。再就是Data帧,用来传输正文实体。多个Data帧属于同一个流。
多路复用:基于二进制分帧,在同一域名下所有访问都是从同一个tcp连接中走,http消息被分解为独立的帧,乱序发送,服务端根据标识符和首部将消息重新组装起来
二、你知道的http请求头有哪些?
HTTP Request Header 请求头
Accept:指定客户端能够接收的内容类型。
Accept-Charset:浏览器可以接受的字符编码集。
Accept-Encoding:指定浏览器可以支持的web服务器返回内容压缩编码类型。
Accept-Language:浏览器可接受的语言。
Accept-Ranges:可以请求网页实体的一个或者多个子范围字段。
AuthorizationHTTP:授权的授权证书。
Cache-Control:指定请求和响应遵循的缓存机制。
Connection:表示是否需要持久连接。(HTTP 1.1默认进行持久连接)
CookieHTTP:请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。
Content-Length:请求的内容长度。
Content-Type:请求的与实体对应的MIME信息。
Date:请求发送的日期和时间。
Expect:请求的特定的服务器行为。
From:发出请求的用户的Email。
Host:指定请求的服务器的域名和端口号。
If-Match:只有请求内容与实体相匹配才有效。
If-Modified-Since:如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码。
If-None-Match:如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变。
If-Range:如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。
If-Unmodified-Since:只在实体在指定时间之后未被修改才请求成功。
Max-Forwards:限制信息通过代理和网关传送的时间。
Pragma:用来包含实现特定的指令。
Proxy-Authorization:连接到代理的授权证书。
Range:只请求实体的一部分,指定范围。
Referer:先前网页的地址,当前请求网页紧随其后,即来路。
TE:客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息。
Upgrade:向服务器指定某种传输协议以便服务器进行转换(如果支持。
User-AgentUser-Agent:的内容包含发出请求的用户信息。
Via:通知中间网关或代理服务器地址,通信协议。
Warning:关于消息实体的警告信息
练习
一、继承apiview写5个接口
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
views.py:
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book = models.Book.objects.all()
bs = BookSerializer(instance=book, many=True)
return Response(bs.data)
def post(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
class BookDetailView(APIView):
def get(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book)
return Response(bs.data)
def put(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
return Response()
serializers.py:
from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
res = models.Book.objects.create(**validated_data)
return res
def update(self, instance, validated_data):
instance.title = validated_data.get('title')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save()
return instance
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!