序列化器的使用
序列化器的使用分两个阶段:
- 在客户端请求时,使用序列化器可以完成对数据的反序列化。
- 在服务器响应时,使用序列化器可以完成对数据的序列化。
序列化的基本使用
使用的还是上一篇博文中使用的数据库
-
先查询出一个学生对象
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)