文章目录
内容介绍
序列化对象是对检索数据或者请求数据判断的最好方式, 省略了繁琐的请求数据的判断以及返回响应数据的遍历。
应用举例
创建一个数据Demo
from datetime import datetime
from rest_framework import serializers, settings
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
nick_name= serializers.CharField()
created = serializers.DateTimeField()
class User:
def __init__(self, username, nick_name, created=None):
self.username = username
self.nick_name = nick_name
self.created = created or datetime.now()
if __name__ == '__main__':
settings.settings.configure()
user = User(username='root', nick_name ='Escaflowne')
serializer = UserSerializer(user)
print(serializer.data)
在上面的代码块中定义了一个用户序列化类,又定义了一个仿造 ORM 的用户类, 并将 User 的实例对象 user 传递给序列化的 data 参数, 将可以生成一个序列化对象, 打印序列化对象的 .data 属性可以获得以下数据
数据渲染成 JSON 对象
from datetime import datetime
from rest_framework import serializers, settings
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
nick_name= serializers.CharField()
created = serializers.DateTimeField()
class User:
def __init__(self, username, nick_name, created=None):
self.username = username
self.nick_name = nick_name
self.created = created or datetime.now()
if __name__ == '__main__':
settings.settings.configure()
from rest_framework.renderers import JSONRenderer
user = User(username='root', nick_name ='Escaflowne')
serializer = UserSerializer(user)
print(JSONRenderer().render(serializer.data))
运行结果
反序列化
from datetime import datetime
import io
from rest_framework import serializers, settings
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
nick_name= serializers.CharField()
created = serializers.DateTimeField()
class User:
def __init__(self, username, nick_name, created=None):
self.username = username
self.nick_name = nick_name
self.created = created or datetime.now()
if __name__ == '__main__':
settings.settings.configure()
from rest_framework.parsers import JSONParser
json = b'{"username": "root", "nick_name": "Escaflowne", "created": "2021-01-21T09:58:35.754067"}'
stream = io.BytesIO(json)
data = JSONParser().parse(stream)
serializer = UserSerializer(data=data)
if serializer.is_valid():
print(serializer.validated_data)
else:
print(serializer.errors)
将保存的序列化数据反序列化一样可以实现,在反序列的时候需要执行 .is_valid() 来判断数据是否符合序列化类声明的对象约束,如果返回 False 说明序列化对象不是符合声明对象的那样,在返回 True 的时候就可以用 serializer.validated_data 获取序列化的数据。
那不符合约束的情况就可以用 serializer.errors 获取错误信息
django.core.exceptions.AppRegistryNotReady: xxxxxxxxxxxxx
保存、更新实例
如果你想使用验证后的数据返回一个新的实例对象,你需要实现 create 或者 update 或者两个方法都实现。在 Django-ORM 中你可能需要做一个保存数据的操作。
from datetime import datetime
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
username = serializers.CharField()
blog = serializers.CharField()
created = serializers.DateTimeField()
def create(self, validated_data):
return User.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.nick_name= validated_data.get('nick_name', instance.nick_name)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
保存实例或者更新实例的 save() 方法, 主要是看你是否在创建实例序列化对象是否传递了对象
# 没有传递实例对象, 所以这是新增
serializer = UserSerializer(data=data)
# 传递了一个 user 对象, 所以这是更新了 user 对象的数据
serializer = UserSerializer(user, data=data)
验证数据
反序列化可以直接调用序列化实例对象的 .is_valid() 方法进行判断约束数据,也可以使用 .is_valid(raise_exception=True) 将错误信息返回给 API 调用者。如果对一个字段需要特殊的判断,可以使用 validate_<field_name> 来进行逻辑判断,<field_name> 是你在序列化类中声明的字段名称。
- 单字段数据判断
from rest_framework import serializers
class UsePostSerializer(serializers.Serializer):
tel = serializers.IntegerField(max_length=11)
email = serializers.EmailField()
def validate_title(self, value):
"""
对 email 字段进行判断
"""
if 'qq.com' not in value:
raise serializers.ValidationError("请使用QQ邮箱,谢谢!")
return value
- 多字段数据判断
from rest_framework import serializers
class UsePostSerializer(serializers.Serializer):
tel = serializers.IntegerField(max_length=11)
tel_urgent = serializers.IntegerField(max_length=11)
email = serializers.EmailField()
def validate(self, data):
"""
判断传递的 start 和 finish 参数是否符合大小逻辑
"""
if data['tel'] = data['tel_urgent']:
raise serializers.ValidationError("联系电话和紧急联系电话不能相同")
return data
- 使用字段约束上直接声明
from rest_framework import serializers
def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('不是10的倍数')
class GameRecord(serializers.Serializer):
score = serializers.IntegerField(validators=[multiple_of_ten])
...
- 声明完整字段验证
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
class EventSerializer(serializers.Serializer):
name = serializers.CharField()
room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
date = serializers.DateField()
class Meta:
validators = [
# 唯一性验证器
UniqueTogetherValidator(
queryset=User.objects.all(),
fields=['username', 'other']
)
]
访问实例和初始数据
将初始对象或查询集传递给序列化实例时,该对象将变为可使用 .instance 属性获取对象,如果没有传递初始对象则 .instance 属性值为 None。
将数据传递给序列化程序实例时,未修改的数据将以 .initial_data 形式提供,如果未传递 data 关键字参数,则该 .initial_data 属性将不存在。
部分更新
from rest_framework import serializers
class UpdateSerializer(serializers.Serializer):
name = serializers.CharField()
room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
date = serializers.DateField()
UpdateSerializer(user, data={
'room_number': 101}, partial=True)
序列化嵌套
处理一个序列化对象的属性是另一个序列化对象
from rest_framework import serializers
class UserSerializer(serializers.Serializer):
email = serializers.EmailField()
username = serializers.CharField(max_length=100)
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
嵌套可以选择接受该 None 值,则应将 required=False 传递给嵌套序列化器
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False)
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
嵌套序列对象是多条数据构成, 则应将 many=True 传递给嵌套序列化
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False)
edits = EditItemSerializer(many=True)
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
反序列化的数据无法通过约束, 那么会错误信息返回至构造字段中
serializer = CommentSerializer(data={
'user': {
'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid() # False, email 和 content 无法通过验证
# 输出错误数据
serializer.errors
# {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}
嵌套对象处理
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
序列化多个对象
queryset = Tags.objects.all()
serializer = TagsSerializer(queryset, many=True)
serializer.data
显示结果
[
{
'id': 0, 'tag_name': 'China', 'tag_slug': 'China_'},
{
'id': 1, 'tag_name': 'Japan', 'tag_slug': 'Japan_'},
{
'id': 2, 'tag_name': 'American', 'tag_slug': 'American_'}
]
额外上下文链接
在某些情况下, 除了要序列化的对象外, 还需要为序列化器提供额外的上下文。
一种常见的情况是如果您使用的是包含超链接关系的序列化程序, 则要求序列化程序有权访问当前请求, 以便它可以正确生成完全合格的 URL。
可以在实例化序列化程序时通过传递 context 参数来提供任意其他上下文
serializer = AccountSerializer(account, context={
'request': request})
serializer.data
{
'id': 6,
'owner': 'denvercoder9',
'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870),
'details': 'http://example.com/accounts/6/details'
}