Request类的源码分析和序列化与反序列化
Request类的源码分析和序列化与反序列化
Request类源码分析
# 源码分析:
self._request = request # 将老的request传给_request
self._data = Empty # 用一个空的占位符给他占起来
self._files = Empty
self._full_data = Empty
def __getattr__(self, attr):
try:
return getattr(self._request, attr) # 在老的request中找attr找到了就返回这个方法
except AttributeError:
return self.__getattribute__(attr)
@property # 伪装成属性的类
def query_params(self):
return self._request.GET # 其实就是老的request.GET
@property # 伪装成属性的类
def data(self):
if not _hasattr(self, '_full_data'): # 首先调用函数将字符串传过去,得到返回的结果为False,取反为True
self._load_data_and_files() # 执行此方法
return self._full_data
def _hasattr(obj, name): # 收到传入的参数直接返回下面逻辑表达式的结果
return not getattr(obj, name) is Empty # 执行反射,找到self._full_data是Empty,所以为True然后取反为False
def _load_data_and_files(self):
if not _hasattr(self, '_data'): # 同理得到返回的结果为False,取反为True
self._data, self._files = self._parse() # 将得到的结果解压赋值给data和files
if self._files: # 如果有文件数据
self._full_data = self._data.copy() # 将数据copy赋值给_full_data
self._full_data.update(self._files) # 并且给其增加一个文件
else:
self._full_data = self._data # 否则,将数据直接赋值给_full_data
if is_form_media_type(self.content_type): # 判断类型是否为form-data或者urlencoded,是则执行以下代码
self._request._post = self.POST
self._request._files = self.FILES
# 总结:
新的request有个有个data属性,body中的任何编码格式的任何请求方式的数据都是他
文件还是request.FILES
其他的属性还是和以前一样只不过经过重写__getattr__后从request._request.方法或属性简化成了request.方法或属性
request.GET可以使用request.query_params
# 魔法方法之 __getattr__, .拦截,对象.属性 当属性不存在时,会触发类中__getattr__的执行
# get请求能不能在body体中带数据
-能
序列化组件介绍
1. 序列化,序列化器会把模型对象(queryset,单个对象)转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request.data以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能
序列化类的基本使用
# 1 创建book表模型
# 2 写查询所有图书的接口:APIView+序列化类+Response
序列化类的实现
views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Publish
from .serializers import PublishSerializer
# Create your views here.
class PublishView(APIView):
back_dic = {'code': 200, 'msg': '成功'}
def get(self, request):
publish = Publish.objects.all()
ser = PublishSerializer(instance=publish, many=True)
self.back_dic['data'] = ser.data
return Response(self.back_dic)
def post(self, request):
ser = PublishSerializer(data=request.data)
if ser.is_valid():
ser.save()
self.back_dic['msg'] = '增加成功'
return Response(self.back_dic)
else:
self.back_dic['code'] = 201
self.back_dic['msg'] = '新增失败'
self.back_dic['errno'] = ser.errors
return Response(self.back_dic)
class PublishDetailView(APIView):
back_dic = {'code': 200, 'msg': '成功'}
def get(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
ser = PublishSerializer(instance=publish)
self.back_dic['data'] = ser.data
return Response(self.back_dic)
def put(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
ser = PublishSerializer(instance=publish, data=request.data)
if ser.is_valid():
ser.save()
self.back_dic['msg'] = '修改成功'
return Response(self.back_dic)
else:
self.back_dic['code'] = 201
self.back_dic['msg'] = '修改失败'
self.back_dic['errno'] = ser.errors
return Response(self.back_dic)
def delete(self, request, pk):
Publish.objects.filter(pk=pk).delete()
return Response()
urls.py
from django.urls import path
from app01.views import *
urlpatterns = [
# path('admin/', admin.site.urls),
path('publish/', PublishView.as_view()),
path('publish/<int:pk>', PublishDetailView.as_view()),
]
序列化类
import re
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import Publish
class PublishSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=10, min_length=2)
addr = serializers.CharField(max_length=20)
phone = serializers.IntegerField()
def validate_name(self, name):
if '东京' in name:
raise ValidationError('出版社名字不能有东京')
return name
def validate_addr(self, addr):
if addr.startswith('上海'):
raise ValidationError('出版社地址开头不能是上海')
return addr
def validate_phone(self, phone):
if not re.match(r'^1[3-9]\d{9}$', str(phone)):
raise ValidationError('手机号码不规范')
return phone
def validate(self, attrs):
name = attrs.get('name')
addr = attrs.get('addr')
if name == addr:
raise ValidationError('出版社名字不能和地址一样')
return attrs
def create(self, validated_data):
publish = Publish.objects.create(**validated_data)
return publish
def update(self, publish, validated_data):
for item in validated_data:
setattr(publish, item, validated_data[item])
publish.save()
return publish
表模型
from django.db import models
# Create your models here.
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
phone = models.IntegerField()
总结
# 序列化类的使用
1 写一个类,继承serializers.Serializer
2 在类中写字段,要序列化的字段
3 在视图类中使用:(多条,单条)
serializer = BookSerializer(instance=book_list, many=True)
serializer = BookSerializer(instance=book)
常用字段类和参数(了解)
常用字段类
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
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) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
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) |
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=) |
# IntegerField CharField DateTimeField DecimalField
# ListField和DictField---》比较重要,但是后面以案例形式讲
字段参数(校验数据来用的)
选项参数:(CharField,IntegerField)
参数名称 | 作用 |
---|---|
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 |
# read_only write_only 很重要,后面以案例讲
反序列化之校验
class PublishSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False) # 字段自己的校验写在括号里
name = serializers.CharField(max_length=10, min_length=2)
addr = serializers.CharField(max_length=20)
phone = serializers.IntegerField()
def validate_name(self, name): # 局部钩子,方法名必须为validate_字段名
if '东京' in name:
raise ValidationError('出版社名字不能有东京')
return name
def validate_addr(self, addr):
if addr.startswith('上海'):
raise ValidationError('出版社地址开头不能是上海')
return addr
def validate_phone(self, phone):
if not re.match(r'^1[3-9]\d{9}$', str(phone)):
raise ValidationError('手机号码不规范')
return phone
def validate(self, attrs): # 全局钩子:方法名必须是 validate
name = attrs.get('name')
addr = attrs.get('addr')
if name == addr:
raise ValidationError('出版社名字不能和地址一样')
return attrs
# 只有三层都通过,在视图类中:
ser.is_valid(): 才是True,才能保存
反序列化之保存
# 在数据校验过后要用序列化类.save()进行保存但是,需要重写几个方法
def create(self, validated_data): # 新增接口
publish = Publish.objects.create(**validated_data)
return publish
def update(self, publish, validated_data): # 修改接口
for item in validated_data:
setattr(publish, item, validated_data[item])
publish.save()
return publish
# 研究了一个问题
在视图类中,无论是保存还是修改,都是调用序列化类.save(),底层实现是根据instance做一个判断
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!