APIView解析使用与序列化组件的解析与适用
APIView解析使用与序列化组件的解析与适用
HTTP协议各版本之间有何区别
-
HTTP是最初的HTTP协议,已经过时
- 特点: 1.只支持GET请求、
2.没有协议头、
3.无状态性、
4.只能传输超文本
- 特点: 1.只支持GET请求、
-
HTTP1.0在请求和响应中加入了HTTP版本号,这一特点在之后的版本中保持不变
- 特点: 1.除了GET命令,新增了POST和HEAD命令。
2.不再只接受HTML数据格式,可以设置contentType传输多种数据格式
3.新增状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等.
- 特点: 1.除了GET命令,新增了POST和HEAD命令。
-
HTTP1.1,这是目前最流行的HTTP协议
- 特点: 1.引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求重复使用
2.请求好响应都支持Host头域,认为每一个服务器都绑定唯一的一个IP地址
3.字节范围请求:若客户端此时已经有一部分数据,为节省宽带,可以只想服务器端请求一部分数据,这个功能在请求头的range头域实现。
4.新增一批Request method:HTTP1.1增加了OPTIONS,PUT,DELETE,TRACE,CONNECT方法
- 特点: 1.引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求重复使用
-
HTTP2.0,为了解决1.1版本利用率不高的问题,提出了HTTP2.0版本。但目前似乎还没流行起来。
- 特点: 1.增加双工模式,也就是不经客户端可以同事发送多个请求,服务端也能处理多个请求,以此来提高利用率,也是这个版本最大的亮点。
2.服务器推送:不经请求向客户端发送数据
3.二进制分帧层
4.数据流,将每个请求或相应的所有数据包成为一个数据流,每个数据流有一个ID,规定客户端发送的ID为奇数,服务端发送的ID为偶数;客户端还可以设置优先级,优先级越高,服务器越先处理
5.头信息压缩机制,由于HTTP很多请求头信息中的字段都一样,可以先压缩后发送,而且客户端和服务器可以同时维护一张头信息表,只用传输索引号,大大提高效率。
- 特点: 1.增加双工模式,也就是不经客户端可以同事发送多个请求,服务端也能处理多个请求,以此来提高利用率,也是这个版本最大的亮点。
-
HTTP3.0,在2018年发布,基于谷歌的QUIC,底层使用的udp代码TCp协议
- 提升: 1.使用stream进一步扩展HTTP2.0的多路复用,传输多少文件就可以产生多少stream,若发生丢包,只需要传输丢失的stream
2.基于UDP,提高了传输效率,降低延迟
3.通过引入Connection Id,是的HTTP/3支持连接迁移以及NAT的重绑定
4.HTTP/3含有油一个包括验证,加密,数据及负载的built-in的TLS安全机制
- 提升: 1.使用stream进一步扩展HTTP2.0的多路复用,传输多少文件就可以产生多少stream,若发生丢包,只需要传输丢失的stream
HTTP请求头都有哪些
-
HTTP请求头的组成
- HTTP请求头提供了关于请求,响应或者其他的发送实体的信息。HTTP的头信息包括通用头、请求头
-
组成四部分
- 通用头标:即可用于请求,也可以用于响应,是作为一个整体而不是特定资源与事务相关联
- 请求头标:允许客户端传递关于自身的信息和希望的响应形式
- 响应头标:服务器和于传递自身信息的响应。
- 实体投标:定义被传送资源的信息.即可用于请求,也可以用于响应.
-
请求头详细了解
HTTP Request Header 请求头 1.Accept:指定客户端能够接收的内容类型。 2.Accept-Charset:浏览器可以接受的字符编码集。 3.Accept-Encoding:指定浏览器可以支持的web服务器返回内容压缩编码类型。 4.Accept-Language:浏览器可接受的语言。 5.Accept-Ranges:可以请求网页实体的一个或者多个子范围字段。 6.AuthorizationHTTP:授权的授权证书。 7.Cache-Control:指定请求和响应遵循的缓存机制。 8.Connection:表示是否需要持久连接。(HTTP 1.1默认进行持久连接) 9.CookieHTTP:请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 10.Content-Length:请求的内容长度。 11.Content-Type:请求的与实体对应的MIME信息。 12.Date:请求发送的日期和时间。 13.Expect:请求的特定的服务器行为。 14.From:发出请求的用户的Email。 15.Host:指定请求的服务器的域名和端口号。 16.If-Match:只有请求内容与实体相匹配才有效。 17.If-Modified-Since:如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码。 18.If-None-Match:如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变。 19.If-Range:如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。 20.If-Unmodified-Since:只在实体在指定时间之后未被修改才请求成功。 21.Max-Forwards:限制信息通过代理和网关传送的时间。 22.Pragma:用来包含实现特定的指令。 23.Proxy-Authorization:连接到代理的授权证书。 24.Range:只请求实体的一部分,指定范围。 25.Referer:先前网页的地址,当前请求网页紧随其后,即来路。 26.TE:客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息。 27.Upgrade:向服务器指定某种传输协议以便服务器进行转换(如果支持。 28.User-AgentUser-Agent:的内容包含发出请求的用户信息。 29.Via:通知中间网关或代理服务器地址,通信协议。 30.Warning:关于消息实体的警告信息
-
响应头详细了解
HTTP Responses Header 响应头 1.Accept-Ranges:表明服务器是否支持指定范围请求及哪种类型的分段请求。 2.Age:从原始服务器到代理缓存形成的估算时间(以秒计,非负)。 3.Allow:对某网络资源的有效的请求行为,不允许则返回405。 4.Cache-Control:告诉所有的缓存机制是否可以缓存及哪种类型。 5.Content-Encodingweb:服务器支持的返回内容压缩编码类型。。 6.Content-Language:响应体的语言。 7.Content-Length:响应体的长度。 8.Content-Location:请求资源可替代的备用的另一地址。 9.Content-MD5:返回资源的MD5校验值。 10.Content-Range:在整个返回体中本部分的字节位置。 11.Content-Type:返回内容的MIME类型。 12.Date:原始服务器消息发出的时间。 13.ETag:请求变量的实体标签的当前值。 14.Expires:响应过期的日期和时间。 15.Last-Modified:请求资源的最后修改时间。 16.Location:用来重定向接收方到非请求URL的位置来完成请求或标识新的资源。 17.Pragma:包括实现特定的指令,它可应用到响应链上的任何接收方。 18.Proxy-Authenticate:它指出认证方案和可应用到代理的该URL上的参数。 19.refresh:应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) 20.Retry-After:如果实体暂时不可取,通知客户端在指定时间之后再次尝试。 21.Serverweb:服务器软件名称。 22.Set-Cookie:设置Http Cookie。 23.Trailer:指出头域在分块传输编码的尾部存在。 24.Transfer-Encoding:文件传输编码。 25.Vary:告诉下游代理是使用缓存响应还是从原始服务器请求。 26.Via:告知代理客户端响应是通过哪里发送的。 27.Warning:警告实体可能存在的问题。 28.WWW-Authenticate:表明客户端请求实体应该使用的授权方案。
APIView基本使用
-
DRF:是一个第三方的app,只能在Django上使用
-
安装了DRF后,导入一个视图类APIView,所有后期要是用drf写的视图类都会继承APIView及其子类
-
使用View+JsonResponse写
from django.views import View from .models import Book from django.http import JsonResponse # Create your views here. 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}) # 返回的数据为了满足序列化的条件我们需要将safe由True变成False,但是我们所显示出来的汉字确实以二进制 # 的形式进行展示,所以我们如果想要看到我们用汉字书写的字那么我们就需要将json_dumps_params的ascii编码变为False return JsonResponse(res_list,safe=False,json_dumps_params={'ensure_ascii':False})
-
使用APIView+drf的Response写(需要调用rest_framework这个APP)
from .models import Book from rest_framework.views import APIView from rest_framework.response import Response # Create your views here. # 如果我们想要使用rest_framework就必须要先在setting中注册app,INSTALLED_APPS = ['rest_framework'] class BookView(APIView): def get(self,request): print(type(self.request)) # <class 'rest_framework.request.Request'> 查看区别 自己多的request print(type(request)) # <class 'rest_framework.request.Request'> 查看区别,父类的request = Request print(request._request) # <class 'rest_framework.request.Request'> 查看区别,本质上还是自己的request print(type(request._request)) # <class 'django.core.handlers.wsgi.WSGIRequest'> # Django在接受http请求之后会根据http请求携带的参数以及报文信息创建一个WSGIRequest对象,并且作为视图函数的 # 赌徒个参数传给视图函数,也就是我们经常看到的request参数。在这个对象上我们可以找到客户端上传来的所有信息。这个 # 对象的完整路径是:django.core.handlers.wsgi.WSGIRequest print(request.method) # GET,我们上方使用哪种请求方式那么都会是哪种请求方式 print(request.path) # /books/查看路径 print(request.GET) # 原来的get请求提交的参数 <QueryDict: {'format': ['api']}> print(request.POST) # 原来的post请求提交的参数由于我们使用的是get所以为空 <QueryDict: {}> book_list = Book.objects.all() res_list = [] for book in book_list: # 返回的数据为了满足序列化的条件我们需要将safe由True变成False,但是我们所显示出来的汉字确实以二进制 # # 的形式进行展示,所以我们如果想要看到我们用汉字书写的字那么我们就需要将json_dumps_params的ascii编码变为False res_list.append({'name':book.name,'price':book.price,'publish':book.publish}) return Response(res_list)
APIView源代码分析
- APIView中的内部源码分析
class APIView(View):
# Python中类常用的几种装饰器
# 1、@classmethod :被classmethod装饰了之后,该方法就是一个类方法,也就是说不需要经过实例化就可以被直接调用
# 2、@staticmethod:静态方法,类实例和类都可以调用;调用静态方法后,此函数就跟普通函数一样,任何参数都需要传入,添加了这个参数不需要实例化就可以被调用,但是就不可以使用cls和self参数
# 3、@propert:设定只读属性,将类函数的执行免去括号,直接调用
@classmethod
def as_view(cls, **initkwargs):
# 我们发现他调用了父类(View)的as_view
view = super().as_view(**initkwargs)
# all other authentication is CSRF exempt.
# 来到这里的所有请求都被取消经过csrf中间件,不会被这个中间件所监测
# 相当于在函数上加装了一个装饰器
'''
@csrf_exempt
def jiasixian(request):
pass
'''
return csrf_exempt(view)
# 经过判断本层其实什么都没有做只是将所有的请求都变得不会经过csrf中间件
- 父类(View)的as_view中的内部源码分析
# 当请求来的时候,路由匹配成功汇之星View类的as_view类方法内的view必报函数(但是由于上层已经将csrf去除那么就会直接执行)
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# 执行self.dispatch→APIView的dispatch
return self.dispatch(request, *args, **kwargs)
return view
- 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
self.headers = self.default_response_headers # deprecate? 这个是开发app的工作人员,看到别的工作人员代码表示不理解,或者不赞同但是又不删除和修改
try:
# 执行了认证,频率与权限
self.initial(request, *args, **kwargs)
# 原来的View的dispatch的东西
# Get the appropriate handler method
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
-
总结
1.我们在APIView中将csrf取消走csrf中间件,也就是说不需要csrf的认证 2.在as_view中使用的request对象,已经变陈改了drf提供的Request类的对象了 3.执行视图类的方法之前,执行了3大认证(认证,权限,频率) 4.在执行三大认证和视图类方法的过程中只要报错那么都会被报错异常捕获 5.最后返回django自带的response
Request类的源代码分析
1.视图类中使用的request对象,已经变成了drf提供的Request类的对象了
1.1 原生的django的request是这个类的对象:
django.core.handlers.wsgi.WSGIRequest
1.2 drf的request是这个类的对象:
rest_framework.request.Request
-
request已经不是原来的request,还能使用原生request的功能嘛?
1.所有的功能依旧可以使用 print(request.method) # GET,我们上方使用哪种请求方式那么都会是哪种请求方式 print(request.path) # /books/查看路径 print(request.GET) # 原来的get请求提交的参数 <QueryDict: {'format': ['api']}> print(request.POST) # 原来的post请求提交的参数由于我们使用的是get所以为空 <QueryDict: {}>
-
Request的源码分析
1.源代码分析 def __getattr__(self, attr): # 如果取的属性不存在会去原生django的request对象中取出来 try: #反射:根据字符串获取属性或方法,self._request 是原来的request return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr) 调用我们自己request所以我们所有的属性和方法都可以和原来一样使用,本质上是通过反射去原来的request中去得 新的Requst内部有个老的request,就是request._request data是个方法,被property装饰了,变成数据属性使用,也就是说可以通过点的方式不需要加括号进行调用,所以body中提交的数据在request.POST中取 query_params:get求提交的参数,等同于request._request.GET或request.GET 其他:取文件也是从request.FILES中取 2.结果验证: 验证:原生的request.POST只有urlencoded和form-data格式的提交数据,json个数的数据在body体重所有我们娶不到,但是在drf中的request有一个data属性,可以取到所提交的任意数据类型的数据
-
回顾魔法方法
- 在类中只要以_ _开头,__结尾的都被称为魔法方法
- 只要是符合某些条件那么不需要手动也可以自动触发并执行
例如:__init__实例化,__str__打印时触发,__call__加括号调用触发,__del__删除时触发,__exit__退出时触发等。
序列化组件简介
1.作用
序列化,序列化器(类)会把模型对象(Book对象,Querset对象)转换成字典,经过response以后变成Json字符串
反序列化,吧客户端发送过来的数据,经过request以后变成字段(request,dat),序列化器(类)可以把字典转成模型
反序列化,完成数据校验功能
2.本质
就是写一个类,继承一个基类,可以完成序列化,反序列化和数据校验
3.drf提供了一种可以快速实现序列化的类,序列化类
序列化组件的基本使用
- 定义一个序列化类
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
- 使用序列化类,序列化多条数据
class BookView(APIView):
def get(self,request):
book_list = Book.objects.all()
# instance表示要序列化的数据,many=True表示序列化多条(instance是request对象,一定要传many=True)
# 以后可以直接添加到数据库中
ser = BookSerializer(instance=book_list,many=True)
return Response(ser.data)
- 使用序列化类,序列化单条数据
class BookDetailView(APIView):
def get(self,request):
book = Book.objects.all()
# 当我们instance表示要序列化的数据,不使用many=True那么就是指序列化一条数据
ser = BookSerializer(instance=book)
return Response(ser.data)
反序列化的基本使用(新增修改)
-
新增,修改→前端传入的数据,要校验→序列化类有数据校验工能
-
新增(视图类)
class BookView(APIView):
def post(self,request):
# 前端传递数据,从request.data取出来
ser = BookSerializer(data=request.data)
# 校验前段传入的数据,没有校验规则也就相当于没有校验
if ser.is_valid():
# 写入数据,这里会报错,调用save会触发BootSerializer的save方法,
# 判断了如果是instance有值执行update,没有执行create
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
- 新增(序列化类)
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
# 我们为了避免save报错我们课可以直接重写create方法,泳衣保存数据
def create(self, validated_data):
res = Book.objects.create(**validated_data)
return res
- 修改(视图类)
class BookView(APIView):
def post(self,request):
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
class BookSerializer(serializers.Serializer):
def update(self, 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
字段和参数补充
常用字段
字段 | 字段构造方式 |
---|---|
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
IntegerField | IntegerField(max_value=None, min_value=None) |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
BooleanField | BooleanField() |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
NullBooleanField | NullBooleanField() |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol=’both’, unpack_ipv4=False, **options) |
FloatField | FloatField(max_value=None, min_value=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
指定参数
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空,传值时可不穿 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用参数
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |