DRF序列化器的使用
序列化器的使用
序列化器的使用分两个阶段:
- 在客户端请求时,使用序列化器可以完成对数据的反序列化。
- 在服务器响应时,使用序列化器可以完成对数据的序列化。
序列化的基本使用
使用的还是上一篇博文中使用的数据库
先查询出一个学生对象
from students.models import Student student = Student.objects.get(id=3)
构造序列化器对象
from .serializers import StudentSerializer serializer = StudentSerializer(instance=student)
获取序列化数据
通过data属性可以获取序列化后的数据
serializer.data
# {'id': 4, 'name': '盖伦', 'age': 18, 'sex': True, 'description': '德玛西亚'}
完整视图代码
from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class StudentRetrieveView(View):
"""使用序列化器序列化转换单个模型数据"""
def get(self,request,pk):
# 获取数据
student = Student.objects.get(pk=pk)
# 数据转换[序列化过程]
serializer = StudentSerializer(instance=student)
print(serializer.data)
# 响应数据
return JsonResponse(serializer.data)
如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
class StudentView(View):
"""使用序列化器序列化转换多个模型数据"""
def get(self,request):
# 获取数据
student_list = Student.objects.all() # 转换数据[序列化过程]
# 如果转换多个模型对象数据,则需要加上many=True
serializer = StudentSerializer(instance=student_list,many=True)
print( serializer.data ) # 序列化器转换后的数据 # 响应数据给客户端
# 返回的json数据,如果是列表,则需要声明safe=False
return JsonResponse(serializer.data,safe=False)
反序列化
数据验证
- 使用序列化器进行反序列化时,首先要对数据进行验证,之后才能获取验证成功的数据或保存成模型类对象。
- 在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
- 验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
- 验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
新建一个子应用books
python manage.py startapp books
在settings.py中的INSTALLED_APPS中新增books子应用
INSTALLED_APPS = [
# ...
'ser',
'unser',
]
定义一个图书的模型和序列化器,
Book模型,代码如下:
from django.db import models
class Book(models.Model):
"""图书模型"""
title = models.CharField(verbose_name='名称', max_length=20)
pub_date = models.DateField(verbose_name='发布日期')
read = models.IntegerField(verbose_name='阅读量',default=0)
comment = models.IntegerField(verbose_name='评论量', null=True, blank=True)
class Meta:
db_table = "tb_book"
verbose_name="图书"
verbose_name_plural=verbose_name
def __str__(self):
return self.title
执行数据迁移,代码:
python manage.py makemigrations
python manage.py migrate
BookSerializer序列化器,代码:
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
title = serializers.CharField(label='名称', max_length=20)
pub_date = serializers.DateField(label='发布日期', required=False)
read = serializers.IntegerField(label='阅读量', required=False)
comment = serializers.IntegerField(label='评论量', required=False)
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
from book.serializers import BookSerializer
data = {'pub_date': 123}
serializer = BookSerializer(data=data)
serializer.is_valid() # 返回False
serializer.errors
# {'title': [ErrorDetail(string='This field is required.', code='required')], 'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data # {}
data = {'title': 'python'}
serializer = BookSerializer(data=data)
serializer.is_valid() # True 验证结果返回值
serializer.errors # {} 错误信息
serializer.validated_data # OrderedDict([('btitle', 'python')])
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:
validate_字段名
对<field_name>字段进行验证,如
class BookSerializer(serializers.Serializer):
"""图书数据序列化器"""
...
def validate_title(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
测试
from book.serializers import BookSerializer
data = {'title': 'python'}
serializer = BookSerializer(data=data)
serializer.is_valid() # False
serializer.errors
# {'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
validate
在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如
class BookSerializer(serializers.Serializer):
"""图书序列化器"""
...
def validate(self, attrs):
read = attrs['read']
comment = attrs['comment']
if read < comment:
raise serializers.ValidationError('阅读量小于评论量,不可以通过')
return attrs
测试
from book.serializers import BookSerializer
data = {'title': 'about django', 'read': 10, 'comment': 20}
s = BookSerializer(data=data)
s.is_valid() # False
s.errors
# {'non_field_errors': [ErrorDetail(string='阅读量小于评论量', code='invalid')]}
validators
在字段中添加validators选项参数,也可以补充验证行为,如
def about_django(value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
class BookSerializer(serializers.Serializer):
"""图书序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
title = serializers.CharField(label='名称', max_length=20, validators=[about_django])
pub_date = serializers.DateField(label='发布日期', required=False)
read = serializers.IntegerField(label='阅读量', required=False)
comment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
测试:
from book.serializers import BookSerializer
data = {'title': 'python'}
serializer = BookSerializer(data=data)
serializer.is_valid() # False
serializer.errors
# {'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
反序列化-保存数据
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
可以通过实现create()和update()两个方法来实现。
class BookSerializer(serializers.Serializer):
"""图书数据序列化器"""
...
def create(self, validated_data):
"""新建"""
return Book(**validated_data)
def update(self, instance, validated_data):
"""更新,instance为要更新的对象实例"""
instance.title = validated_data.get('title', instance.title)
instance.pub_date = validated_data.get('pub_date', instance.pub_date)
instance.read = validated_data.get('read', instance.read)
instance.comment = validated_data.get('comment', instance.comment)
return instance
如果需要在返回数据对象的时候,也将数据保存到数据库中,则可以进行如下修改
class BookSerializer(serializers.Serializer):
"""图书数据序列化器"""
...
def create(self, validated_data):
"""新建"""
return Book.objects.create(**validated_data)
def update(self, instance, validated_data):
"""更新,instance为要更新的对象实例"""
instance.title = validated_data.get('title', instance.title)
instance.pub_date = validated_data.get('pub_date', instance.pub_date)
instance.read = validated_data.get('read', instance.read)
instance.comment = validated_data.get('comment', instance.comment)
instance.save()
return instance
实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
book = serializer.save()
如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。
from .serializers import BookSerializer
data = {'title': 'python入门指南'}
serializer = BookSerializer(data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: python入门指南>
from .models import Book
book = Book.objects.get(id=2)
data = {'title': 'django入门指南'}
serializer = BookSerializer(book, data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: django入门指南>
book.title # 'django入门指南'
附加说明
在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到
# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=request.user)
默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
模型类序列化器
经过前边的实验,有没有一种疑问,就是我们能不能使用序列化器对应的是Django中的模型类?如果可以的话,就不需要我们对照models模型进行数列化器的设计了。考虑到广大攻城狮的时间成本,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
- 基于模型类自动生成一系列字段
- 基于模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
定义
比如我们创建一个BookSerializer
class BookSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = Book
fields = '__all__'
- model 指明参照哪个模型类
- fields 指明为模型类的哪些字段生成
我们可以在python manage.py shell中查看自动生成的BookSerializer的具体实现
>>> from booktest.serializers import BookSerializer
>>> serializer = BookSerializer()
>>> serializer
BookSerializer():
id = IntegerField(label='ID', read_only=True)
title = CharField(label='名称', max_length=20)
pub_date = DateField(allow_null=True, label='发布日期', required=False)
read = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
comment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
指定字段
- 使用fields来明确字段,
__all__表名包含所有字段,也可以写明具体哪些字段,如
class BookSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = Book
fields = "__all__"
- 使用exclude可以明确排除掉哪些字段
class BookSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = Book
exclude = ('pub_date',)
- 显示指明字段,如:
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id', 'title', 'comment', 'read')
- 指明只读字段
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookSerializer(serializers.ModelSerializer):
"""图书序列化器"""
class Meta:
model = Book
fields = ('id', 'title', 'pub_date', 'read', 'comment')
read_only_fields = ('id', 'read', 'comment')
添加额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookSerializer(serializers.ModelSerializer):
"""图书序列化器"""
class Meta:
model = Book
fields = ('id', 'title', 'pub_date', 'read', 'comment')
extra_kwargs = {
'read': {'min_value': 0, 'required': True},
'comment': {'min_value': 0, 'required': True},
}
# BookSerializer():
# id = IntegerField(label='ID', read_only=True)
# title = CharField(label='名称', max_length=20)
# pub_date = DateField(allow_null=True, label='发布日期', required=False)
# read = IntegerField(label='阅读量', max_value=2147483647, min_value=0, required=True)
# comment = IntegerField(label='评论量', max_value=2147483647, min_value=0, required=True)
DRF序列化器的使用的更多相关文章
- drf序列化器serializers.SerializerMethodField()的用法
问题描述: 为什么DRF中有时候返回的json中图片是带域名的,有时候是不带域名的呢? 解析: 带域名的结果是在view中对模型类序列化的,DRF在序列化图片的时候 会检查上下文有没有request, ...
- drf序列化器的实例
应用目录结构: views.py from django.shortcuts import render # Create your views here. from django.views imp ...
- DRF序列化器
序列化器-Serializer 作用: 1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 反序列化,把客户端发送过来的数据,经过request以后变成字典 ...
- DRF 序列化器-Serializer (2)
作用 1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 完成数据校验功能 3. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器 ...
- drf序列化器与反序列化
什么是序列化与反序列化 """ 序列化:对象转换为字符串用于传输 反序列化:字符串转换为对象用于使用 """ drf序列化与反序列化 &qu ...
- 对drf序列化器的理解
序列化: 将对象的状态信息转换为可以存储或传输的形式的过程.(百度定义) 对应到drf中,序列化即把模型对象转换为字典形式, 再返回给前端,主要用于输出 反序列化: 把其他格式转化为程序中的格式. 对 ...
- 关于定义序列化器时,read_only和write_only有什么作用
关于序列化和反序列化 在谈论前,先说一下序列化和反序列化,这两个概念最初是在学习json的时候提出来的,回头来看,其实可以用最初的理解就可以了 序列化就是将对象转化方便传输和存储字节序列,例如js ...
- 一: DRF web应用框架基础,及序列化器的使用
---恢复内容开始--- 一: web 应用模式(有两种) 1: 前后端不分离(前端从后端直接获取数据) 2: 前后端分离 二: api 接口 原因一: 为了在团队内部形成共识.防止个人习惯差异引起的 ...
- DRF中的序列化器
DRF中的序列化器详细应用 视图的功能:说白了就是接收前端请求,进行数据处理 (这里的处理包括:如果前端是GET请求,则构造查询集,将结果返回,这个过程为序列化:如果前端是POST请求,假如要对数 ...
随机推荐
- 从mysql8.0读取数据并形成pandas dataframe类型数据,精确定位行列式中的元素,并读取
from pandas import * import pandas as pd from sqlalchemy import create_engine engine = create_engine ...
- ZOJ4019——贪心&&DP
题目 链接 大意:有一个容量为$c$的背包,有$n$个$s_1$类物体,价值都为$k_1$,体积分别为$s_{1,1}, s_{1,2}, \cdots, s_{1,n}$,有$m$个$s_2$类物体 ...
- 06-vue项目02:vuex、Mutation、Action、ElementUI、axios
1.Vuex 1.为什么使用VueX data从最上面的组件,一层层往下传值,一层层的验证 Vue单向数据流 “中央空调“,代理 VueX 解决数据 传值.. 2.Vuex介绍与安装 (1)Vuex官 ...
- Mybatis的mapper接口在Spring中实例化过程
在spring中使用mybatis时一般有下面的配置 <bean id="mapperScannerConfigurer" class="org.mybatis.s ...
- CF732D Exams 二分 贪心
思路:二分+贪心 提交次数:10次以上 错因:刚开始以为二分(边界,$+1or-1$)写错了,调了半天,后来才发现是$ck()$写错了.开始只判了最后是否小于零,而应该中间一旦小于零就$return\ ...
- LinkedBlockingQueue 实现 生产者 消费者
转载:https://blog.csdn.net/sinat_36553913/article/details/79533606 Java中使用LinkedBlockingQueue实现生产者,消费者 ...
- Task , Thread 学习
1.任务StartNew后就开始执行,使用Wait()来确保任务结束后继续 static void Main(string[] args) { try { int numberOfUsers = 10 ...
- .net实现浏览器大文件分片上传
以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传 ...
- diff:二进制文件内容差异比较
在Ubuntu 18.04下验证,造冰箱的大熊猫@cnblogs 2019/7/29 假设我们需要以二进制格式比较两个文件file1.bin和file2.bin的差异,一个简单的方法是 1)先使用xx ...
- codeforces865C
Gotta Go Fast CodeForces - 865C You're trying to set the record on your favorite video game. The gam ...