• Django REST framework中的序列化Serializers


    序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python 数据类型,然后可以将它们轻松地呈现为 JSON,XML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。
    简单来说,服务器通过api 返回数据(json格式),把非json格式转换为json 就是序列化的过程
    浏览器提交给服务器端的数据,服务端将json 格式转换给非json存储到数据库,就是反序列化

    REST framework 中的序列化类与 Django 的 Form 和 ModelForm 类非常相似。我们提供了一个 Serializer 类,它提供了一种强大的通用方法来控制响应的输出,以及一个 ModelSerializer 类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式。

    1、申明序列化类

    首先创建一个简单的对象用于示例:

    from datetime import datetime
    class Comment(object):
        def __init__(self, email, content, created=None):
            self.email = email
            self.content = content
            self.created = created or datetime.now()
    comment = Comment(email='leila@example.com', content='foo bar')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    声明一个序列化类,使用它来序列化和反序列化与 Comment 对象相对应的数据
    声明一个序列化类看起来非常类似于声明一个表单:

    from rest_framework import serializers
    class CommentSerializer(serializers.Serializer):
        email = serializers.EmailField()
        content = serializers.CharField(max_length=200)
        created = serializers.DateTimeField()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、序列化对象

    现在可以使用 CommentSerializer 来序列化评论或评论列表。同样,使用 Serializer 类看起来很像使用 Form 类。

    serializer = CommentSerializer(comment)
    serializer.data
    # {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
    
    • 1
    • 2
    • 3

    此时已经将模型实例转换为 Python 原生数据类型。为了完成序列化过程,将数据渲染为 json。

    from rest_framework.renderers import JSONRenderer
    json = JSONRenderer().render(serializer.data)
    json
    # b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
    
    • 1
    • 2
    • 3
    • 4

    3、反序列化对象

    反序列化是相似的。首先我们将一个流解析为 Python 原生数据类型

    from django.utils.six import BytesIO
    from rest_framework.parsers import JSONParser
    stream = BytesIO(json)
    data = JSONParser().parse(stream)
    
    • 1
    • 2
    • 3
    • 4

    然后我们将这些原生数据类型恢复成通过验证的数据字典。

    serializer = CommentSerializer(data=data)
    serializer.is_valid()
    # True
    serializer.validated_data
    # {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4、保存实例

    如果希望能够基于验证的数据返回完整的对象实例,则需要实现 .create() 和 .update() 方法中的一个或两个。例如:

    class CommentSerializer(serializers.Serializer):
        email = serializers.EmailField()
        content = serializers.CharField(max_length=200)
        created = serializers.DateTimeField()
        def create(self, validated_data):
            return Comment(**validated_data)
        def update(self, instance, validated_data):
            instance.email = validated_data.get('email', instance.email)
            instance.content = validated_data.get('content', instance.content)
            instance.created = validated_data.get('created', instance.created)
            return instance
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果对象实例与 Django 模型相对应,还需要确保这些方法将对象保存到数据库。如果 Comment 是一个 Django 模型,这些方法可能如下所示:

     def create(self, validated_data):
            return Comment.objects.create(**validated_data)
        def update(self, instance, validated_data):
            instance.email = validated_data.get('email', instance.email)
            instance.content = validated_data.get('content', instance.content)
            instance.created = validated_data.get('created', instance.created)
            instance.save()
            return instance
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    现在,当反序列化数据时,我们可以调用 .save() 根据验证的数据返回一个对象实例。

    comment = serializer.save()
    
    • 1

    调用 .save() 将创建一个新实例或更新现有实例,具体取决于在实例化序列化类时是否传递了现有实例:

    # .save() will create a new instance.
    serializer = CommentSerializer(data=data)
    # .save() will update the existing `comment` instance.
    serializer = CommentSerializer(comment, data=data)
    
    • 1
    • 2
    • 3
    • 4

    .create() 和 .update() 方法都是可选的。您可以都不实现,或者实现其中的一个或两个,具体取决于你的序列化类的用例。

    将附加属性传递给 .save()

    有时你会希望你的视图代码能够在保存实例的时候注入额外的数据。这些附加数据可能包含当前用户,当前时间或其他任何不属于请求数据的信息。

    serializer.save(owner=request.user)
    
    • 1

    调用 .create() 或 .update() 时,任何其他关键字参数都将包含在 validated_data 参数中。

    直接覆盖 .save()。

    在某些情况下,.create() 和 .update() 方法名称可能没有意义。例如,在 “联系人表单” 中,我们可能不会创建新实例,而是发送电子邮件或其他消息。

    在这些情况下,可以选择直接覆盖 .save(),因为它更具可读性和有意义性。

    举个例子:

    class ContactForm(serializers.Serializer):
        email = serializers.EmailField()
        message = serializers.CharField()
        def save(self):
            email = self.validated_data['email']
            message = self.validated_data['message']
            send_email(from=email, message=message)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    请注意,在上面的情况下,必须直接访问 serializer .validated_data 属性。

    5、验证

    在反序列化数据时,你总是需要在尝试访问验证数据之前调用 is_valid(),或者保存对象实例。如果发生任何验证错误,那么 .errors 属性将包含一个代表错误消息的字典。例如:

    serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
    serializer.is_valid()
    # False
    serializer.errors
    # {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    字典中的每个键都是字段名称,值是与该字段相对应的错误消息(字符串列表)。non_field_errors 键也可能存在,并会列出任何常规验证错误。可以使用 NON_FIELD_ERRORS_KEY (在 settings 文件中设置)来定制 non_field_errors 关键字的名称。

    反序列化 item 列表时,错误将作为代表每个反序列化 item 的字典列表返回。

    数据验证时抛出异常
    .is_valid() 方法带有一个可选的 raise_exception 标志,如果存在验证错误,将导致它引发 serializers.ValidationError 异常。
    这些异常由 REST framework 提供的默认异常处理程序自动处理,并且默认情况下将返回 HTTP 400 Bad Request

    # Return a 400 response if the data was invalid.
    serializer.is_valid(raise_exception=True)
    
    • 1
    • 2

    字段级验证
    你可以通过向 Serializer 子类添加 .validate_ 方法来指定自定义字段级验证。这些与 Django 表单上的 .clean_ 方法类似。
    这些方法只有一个参数,就是需要验证的字段值。

    您的 validate_ 方法应返回验证值或引发 serializers.ValidationError。

    from rest_framework import serializers
    class BlogPostSerializer(serializers.Serializer):
        title = serializers.CharField(max_length=100)
        content = serializers.CharField()
        def validate_title(self, value):
            """
            Check that the blog post is about Django.
            """
            if 'django' not in value.lower():
                raise serializers.ValidationError("Blog post is not about Django")
            return value
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对象级验证
    如果要对多个字段进行其他的验证,请将一个名为 .validate() 的方法添加到您的 Serializer 子类中。这个方法只有一个参数,它是一个字段值(field-value)的字典。如果有必要,它应该引发一个 ValidationError,或者只是返回验证的值。例如:

    from rest_framework import serializers
    class EventSerializer(serializers.Serializer):
        description = serializers.CharField(max_length=100)
        start = serializers.DateTimeField()
        finish = serializers.DateTimeField()
        def validate(self, data):
            """
            Check that the start is before the stop.
            """
            if data['start'] > data['finish']:
                raise serializers.ValidationError("finish must occur after start")
            return data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    验证器
    序列化器上的各个字段可以包含验证器,方法是在字段实例上声明它们,例如:

    def multiple_of_ten(value):
        if value % 10 != 0:
            raise serializers.ValidationError('Not a multiple of ten')
    class GameRecord(serializers.Serializer):
        score = IntegerField(validators=[multiple_of_ten])
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    序列化类还可以包含应用于整个字段数据集的可重用验证器。这些验证器是通过在内部的 Meta 类中声明它们来包含的,如下所示:

    class EventSerializer(serializers.Serializer):
        name = serializers.CharField()
        room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
        date = serializers.DateField()
        class Meta:
            # Each room only has one event per day.
            validators = UniqueTogetherValidator(
                queryset=Event.objects.all(),
                fields=['room_number', 'date']
            )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    2.1Java内存模型之JMM内存模型规范详解
    MySQL 的 C 语言接口
    七天.NET 8操作SQLite入门到实战 - 第五天引入SQLite-net ORM并封装常用方法
    【从零开始学习 SystemVerilog】7.1、SystemVerilog 类—— Class 概述
    多目标哈里斯鹰优化 (MOHHO)(Matlab代码实现)
    Redis的使用(四)常见使用场景-缓存使用技巧
    电容式触摸按键功能的实现
    软件设计与体系结构简答题汇总
    Typora消失的图片?
    敏捷管理是PMP体系中的一部分,还是另一种体系?
  • 原文地址:https://blog.csdn.net/javascript_good/article/details/132672405