DRF之新的request源码分析、序列化组件介绍、序列化类,序列化器和单个对象,常用字段类型和字段参数、反序列化的校验、反序列化的之保存
文章目录
一、新的request源码分析
# 源码中找出来,从Request查找
from rest_framework.request import Request
# 进入到Request模块中
class Request:
# Request的方法里面的request就是老的request,它是之前从APIView里面的dispatch里面的request传过来的
'''
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# 这下面一行代码就是APIView里面的dispatch把老的request传递给新的request
# request新的(rest_framework.request.Request) = request老的(django.core.handlers.wsgi.WSGIRequest)
request = self.initialize_request(request, *args, **kwargs)
'''
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
assert isinstance(request, HttpRequest), (
'The `request` argument must be an instance of '
'`django.http.HttpRequest`, not `{}.{}`.'
.format(request.__class__.__module__, request.__class__.__name__)
)
# 这里就是把之前的老的赋值给新的_request
self._request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty
# 由上面可知在Request模块中,一定由方法实现request新老交互的功能
def __getattr__(self, attr):
"""
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
# 新的_request重写了__getattr__,通过反射获取老的request中的属性
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
# APIView+Response写个接口
# 视图层里面的代码
import json
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
class BookView(APIView):
def get(self, request):
# # print(request.POST)
# print(request.GET)
# print('---',request.query_params)
# print(request.data)
print(type(request._request))
print(request._request.GET)
return Response('ook')
def post(self, request):
# request是新的
print(type(request)) # rest_framework.request.Request
# 以后,无论post还是put请求放在body体中的数据,无论那种编码格式,都是从request.data中取
# print(request.data) # 原来的的request没有data属性,新的有了
# 原来的request.POST 还有
# print(request.POST)
# 提交文件form-data格式,还在 request.FILES中
# print(request.FILES)
# 其他的所有属性,都跟之前一模一样
print(request.method)
print(request.body)
print(request.path)
return Response('ok') # Response跟JsonResponse很像,可以传字符串,列表,字典都可以,就是不能传对象
# 总结:
1 新的request有个data属性,以后只要是在请求body体中的数据,无论什么编码格式,无论什么请求方式
2 取文件还是从:request.FILES
3 取其他属性,跟之前完全一样 request.method ....
-原理是:新的Request重写了__getattr__,通过反射获取老的request中的属性
4 request.GET 现在可以使用 request.query_params
@property
def query_params(self):
return self._request.GET
# 源码中找出来
-老的request在新的request._request
-照常理来讲,如果取method,应该request._request.method,但是我现在可以request.method
# 魔法方法之 __getattr__, . 拦截,对象.属性 当属性不存在时,会触发 类中 __getattr__的执行
# get请求能不能在body体中带数据
-能
-以后只要继承了APIView及其子类,视图类中的方法中的request已经不是原来的request了
-request.data 无论任何请求,body体中携带的数据,到了后端,全都放到它中,是个字典
-前端传入的文件,request.FILES中取
-get请求提交的数据【在请求地址中的数据】---》后端request.GET-->request.query_params
-method,path,之前用过的,都是从 request.取得值即可
-魔法方法 __getattr__ . 拦截 对象.属性 如果对象中不存在这个属性,就会触发__getattr__的执行,__getattr__返回什么,就拿到什么
request.path发__getattr__(self, attr) ---->attr='path' request中根据字符串取出'path'
二、序列化组件介绍
2.1、 序列化器-Serializer
Serializer的作用:
- 序列化,序列化器会把模型对象(queryset,单个对象)转换成字典,经过response以后变成json字符串
- 反序列化,把客户端发送过来的数据,经过request.data以后变成字典,序列化器可以把字典转成模型
- 反序列化,完成数据校验功能
2.2、 定义序列化器
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
1、例如,我们已有了一个数据库模型类Book (在models.py文件中创建表)
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=64)
price = models.IntegerField()
2、我们想为这个模型类提供一个序列化器,可以定义如下:创建序列化器Serializer (这里的意思是创建一个Serializer.py的文件夹用来创建序列化类)
# 新建一个序列化器
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
from rest_framework.exceptions import ValidationError
from .models import Book
class Bookserializers(serializers.Serializer):
# 1. 需要进行数据转换的字段( 要序列化的字段 )
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 要序列化的字段
id = serializers.IntegerField()
name = serializers.CharField()
price = serializers.IntegerField()
# 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息
。。。
# 3. 验证代码
。。。
# 4. 编写添加和更新模型的代码
。。。
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
三、 序列化类的基本使用(基于APIView+序列化类+Response实现book表的查询所有or单个的接口功能,)
3.1、创建单表模型(即orm单表查询出来的对象)
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=64)
price = models.IntegerField()
3.2、创建序列化类(创建一个Serializer.py的文件夹,用来完成数据的序列化)
使用序列化类,完成序列化 两个很重要参数: instance实例,对象 data:数据
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 要序列化的字段
id = serializers.IntegerField()
name = serializers.CharField()
price = serializers.IntegerField()
3.3、设置路由
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 开始接口
path('bookint/', views.Bookint.as_view()),
path('book/<int:pk>/', views.Bookintdan.as_view()),
]
3.4、视图类的代码
import json
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
#导入表模型
from .models import Book
# 导入序列化类
from .serializer import BookSerializer
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
# 使用序列化类,完成序列化 两个很重要参数: instance实例,对象 data:数据
# 如果是多条many=True 如果是queryset对象,就要写
# 如果是单个对象 many=False,默认是False
serializer = BookSerializer(instance=book_list, many=True)
# serializer.data # 把qs对象,转成列表套字典 ReturnList
# print(serializer.data)
# print(type(serializer.data))
# return Response(serializer.data)
return Response({'code': 100, 'msg': '成功', 'data': serializer.data})
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.all().get(pk=pk)
serializer = BookSerializer(instance=book)
return Response({'code': 100, 'msg': '成功', 'data': serializer.data})
3.5、postman展示
postman查询一条
查询所有
3.6、总结
# 序列化类的使用
1 写一个类,继承serializers.Serializer
2 在类中写字段,要序列化的字段
3 在视图类中使用:(多条,单条)
serializer = BookSerializer(instance=book_list, many=True)
serializer = BookSerializer(instance=book)
四、常用字段类型
常用字段类型:
### 4.1 常用字段类
| **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(max*length=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=) |
五、字段参数
'''
选项参数:
参数名称 作用
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页面时,显示的字段帮助提示信息
'''
六、反序列化的校验
# 反序列化,有三层校验
-1 字段自己的(写的字段参数:required max_length 。。。)
-2 局部钩子:写在序列化类中的方法,方法名必须是 validate_字段名
def validate_name(self, name):
if 'sb' in name:
# 不合法,抛异常
raise ValidationError('书名中不能包含sb')
else:
return name
-3 全局钩子:写在序列化类中的方法 方法名必须是 validate
def validate(self, attrs):
price = attrs.get('price')
name = attrs.get('name')
if name == price:
raise ValidationError('价格不能等于书名')
else:
return attrs
# 只有三层都通过,在视图类中:
ser.is_valid(): 才是True,才能保存
七、反序列化的之保存
# 新增接口:
-序列化类的对象,实例化的时候:ser = BookSerializer(data=request.data)
-数据校验过后----》调用 序列化类.save()--->但是要在序列化类中重写 create方法
def create(self, validated_data):
book=Book.objects.create(**validated_data)
return book
# 修改接口
-序列化类的对象,实例化的时候:ser = BookSerializer(instance=book,data=request.data)
-数据校验过后----》调用 序列化类.save()--->但是要在序列化类中重写 update方法
def update(self, book, validated_data):
for item in validated_data: # {"name":"jinping","price":55}
setattr(book, item, validated_data[item])
book.save()
return book
# 研究了一个问题
在视图类中,无论是保存还是修改,都是调用序列化类.save(),底层实现是根据instance做一个判断
八、代码展示
8.1、视图层代码
from rest_framework.views import APIView
from app01 import models
from rest_framework.response import Response
from .serializer import Bookserializers
class Bookint(APIView):
# 查询所有数据
def get(self, request):
books_obj = models.Book.objects.all()
# print(books_obj) # QuerySet 的对象
# 使用序列化类,完成序列化 两个很重要参数: instance实例,对象 data:数据
# 如果是多条many=True 如果是queryset对象,就要写
# 如果是单个对象 many=False,默认是False
res = Bookserializers(instance=books_obj, many=True) # 使用序列化器序列化数据
print(res.data) # 得到的是OrderedDict 把 QuerySet对象,转成列表套字典 ReturnList
print(type(res.data)) # <class 'rest_framework.utils.serializer_helpers.ReturnList'>
return Response({"code": 200, 'msg': '成功', 'data': res.data})
# 新增数据
def post(self, request):
# 前端会传入数据,request.data--->把这个数据保存到数据库中
# 借助于序列化类,完成 校验和反序列化
# data 前端传入的数据 {"name":"三国演义","price":88}
print(request.data)
# 接收前端数据进行反序列化
ser = Bookserializers(data=request.data) # 反序列化前端的数据
# data=request.data 是把数据传入序列化器中进行数据处理
# 校验数据
if ser.is_valid(): # 三层:字段自己的校验,局部钩子校验,全局钩子校验 写在
print(ser.validated_data) # validated_data:校验过后的数据
# 校验之后要保存数据
# 如果没有save,如何保存,自己做
# Book.objects.create(**ser.validated_data)
ser.save() # 会保存,但是会报错,因为它不知道你要保存到那个表中
return Response({"code": 200, 'msg': '新增成功'})
else:
print(ser.errors) # 校验失败的错误
return Response({"code": 200, 'msg': '新增失败', 'data': ser.errors})
class Bookintdan(APIView):
def get(self, request, pk):
res_obj = models.Book.objects.all().get(pk=pk)
print(res_obj)
res = Bookserializers(instance=res_obj, many=False) # 序列化 单条数据是many可以不写
print(res.data)
return Response({"code": 200, 'msg': '成功', 'data': res.data})
# 修改一条数据
def put(self, request, pk):
book = models.Book.objects.get(pk=pk)
ser = Bookserializers(instance=book, data=request.data)
if ser.is_valid():
ser.save() # 也会报错,重写update
return Response({"code": 200, 'msg': '修改成功'})
else:
return Response({"code": 200, 'msg': '修改失败', 'data': ser.errors})
# 删除一条数据
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).first().delete()
return Response({"code": 200, 'msg': '删除成功'})
8.2、路由层代码
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 开始接口
path('bookint/', views.Bookint.as_view()),
path('book/<int:pk>/', views.Bookintdan.as_view()),
]
8.3、序列化器的代码
# 新建一个序列化器
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
from rest_framework.exceptions import ValidationError
from .models import Book
class Bookserializers(serializers.Serializer):
# 1. 需要进行数据转换的字段( 要序列化的字段 )
id = serializers.IntegerField(required=False) # 前端传入数据,可以不填这个字段
name = serializers.CharField(allow_blank=True, required=False, max_length=8,
min_length=3, error_messages={'max_length': '数据太长了'}
) # # allow_blank: 这个字段传了,value值可以为空
peice = serializers.IntegerField()
# 局部钩子:给某个字段做个校验
# # 书名中不能包含sb
# # validate_字段名
def validate_name(self, name):
if 'sb' in name:
raise ValidationError('书名中不能包含sb‘')
else:
return name
def validate_price(self, item):
if item == 88:
raise ValidationError('价格不能等于88')
else:
return item
# 全局钩子
def validate(self, attrs):
name = attrs.get('name')
price = attrs.get('price')
if name == price:
raise ValidationError('价格不能等于书名')
else:
return attrs
def create(self, validated_data):
# 通过 validated_data 三层校验之后的数据是字典
# 把字典打撒传到validated_data中
# validated_data 数据是前端传来的
book = Book.objects.create(**validated_data)
return book
def update(self, instance, validated_data):
# instance 要修改的对象 接收前端的book
# validated_data:前端传入,并且校验过后的数据 接收前端的request.data
instance.name = validated_data.get('name')
instance.price = validated_data.get("price")
instance.save()
'''
for item in validated_data:
setattr(book, item, validated_data[item])
instance.save()
# 等同于下面
# setattr(book,'name','jinping')
# setattr(book,'price',55)
# 等同于
# book.name = validated_data.get('name')
# book.price = validated_data.get('price')
'''
return instance
8.4、模型层代码
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=64)
peice = models.IntegerField()
8.5、postman展示
数据库的数据展示
postnam操作:
新增一条数据
修改一条数据
删除一条数据
总结
以上就是今天要讲的内容,本文仅仅简单介绍了 序列化和反序列化 的使用。