【Django Rest framework】Serializers 业务逻辑篇翻译及应用举例

内容介绍

序列化对象是对检索数据或者请求数据判断的最好方式, 省略了繁琐的请求数据的判断以及返回响应数据的遍历。

应用举例

创建一个数据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> 是你在序列化类中声明的字段名称。

  1. 单字段数据判断
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
  1. 多字段数据判断
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

  1. 使用字段约束上直接声明
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])
    ...
  1. 声明完整字段验证
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'
}

猜你喜欢

转载自blog.csdn.net/qq_20288327/article/details/112992696
今日推荐