Python 学习笔记(十六)--Django REST Framework之serializers,反序列化:把客户端发


1.序列化组件介绍

序列化:序列化器会把模型对象转换成字典,经过response以后变成json字符串。

反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型。反序列化,可以完成数据校验功能。

2.引入方式

from rest_framework import serializers

3.类的方法和属性

 4.序列化类的使用

(1)序列化类,继承 serializers.Serializer (或 serializers.ModelSerializer);

 (2)在类中,

         为 serializers.Serializer是,明确需要序列化的字段(逐一指明需要的字段);

         为 serializers.ModelSerializer,明确 class Meta: 信息。

(3)在视图类中使用:导入序列化类,把要序列化的对象传入, 实例化得到序列化类的对象。【要序列化谁,就把谁传过来,其实就是调用类的__init__,看源码是需注意:这个方法来自父类BaseSerializer

(4)序列化类的对象.data是一个字典(注意:不是json)。

(5)使用rest_framework.response中的Response,会以Json的形式把字典里面的数据返回。      from rest_framework.response import Response  【如果不使用这个Response,就需要使用JsonResponse (from django.http import JsonResponse)】

5.序列化类的常见字段类型

serializers.CharField()

serializers.IntegerField()

serializers.IntegerField()

serializers.BooleanField()

serializers.ChoiceField()

serializers.JSONField()

7.数据验证(一般用在反序列化)

Serializer中的validate方法:
    def validate(self, attrs):
        return attrs

父类BaseSerializer有个is_valid方法

    def is_valid(self, raise_exception=False):
        assert hasattr(self, 'initial_data'), (
            'Cannot call `.is_valid()` as no `data=` keyword argument was '
            'passed when instantiating the serializer instance.'
        )

        if not hasattr(self, '_validated_data'):
            try:
                self._validated_data = self.run_validation(self.initial_data)
            except ValidationError as exc:
                self._validated_data = {}
                self._errors = exc.detail
            else:
                self._errors = {}

        if self._errors and raise_exception:
            raise ValidationError(self.errors)

        return not bool(self._errors)
is_valid 返回true 表示验证通过。
注意:不能直接对象.save() , 否则会报错 --NotImplementedError: 'update()' must be implemented。

8.报错原因

Serializer中没有save方法,只是父类BaseSerializer有个save方法.

    def save(self, **kwargs):
        assert hasattr(self, '_errors'), (
            'You must call `.is_valid()` before calling `.save()`.'
        )

        assert not self.errors, (
            'You cannot call `.save()` on a serializer with invalid data.'
        )

        # Guard against incorrect use of `serializer.save(commit=False)`
        assert 'commit' not in kwargs, (
            "'commit' is not a valid keyword argument to the 'save()' method. "
            "If you need to access data before committing to the database then "
            "inspect 'serializer.validated_data' instead. "
            "You can also pass additional keyword arguments to 'save()' if you "
            "need to set extra attributes on the saved model instance. "
            "For example: 'serializer.save(owner=request.user)'.'"
        )

        assert not hasattr(self, '_data'), (
            "You cannot call `.save()` after accessing `serializer.data`."
            "If you need to access data before committing to the database then "
            "inspect 'serializer.validated_data' instead. "
        )

        validated_data = {**self.validated_data, **kwargs}

        if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )

        return self.instance

父类中还有个update()

    def update(self, instance, validated_data):
        raise NotImplementedError('`update()` must be implemented.')

就是这个汇报的错误。

 所以,需要在序列化类中,重新这个update方法。重写时,需要注意,instance代表的是序列化类对象,validated_data是校验后的数据。赋值后,不要忘记保存和返回。

        instance.save()
        return instance

9. 有必要看下父类BaseSerializer的代码,特别是__init__,需要留意的是data参数。

在视图类中,一般通过     序列化类(instance=model的对象, data=request.data),这种格式进行反序列化。

class BaseSerializer(Field):
    """
    The BaseSerializer class provides a minimal class which may be used
    for writing custom serializer implementations.

    Note that we strongly restrict the ordering of operations/properties
    that may be used on the serializer in order to enforce correct usage.

    In particular, if a `data=` argument is passed then:

    .is_valid() - Available.
    .initial_data - Available.
    .validated_data - Only available after calling `is_valid()`
    .errors - Only available after calling `is_valid()`
    .data - Only available after calling `is_valid()`

    If a `data=` argument is not passed then:

    .is_valid() - Not available.
    .initial_data - Not available.
    .validated_data - Not available.
    .errors - Not available.
    .data - Available.
    """

    def __init__(self, instance=None, data=empty, **kwargs):
        self.instance = instance
        if data is not empty:
            self.initial_data = data
        self.partial = kwargs.pop('partial', False)
        self._context = kwargs.pop('context', {})
        kwargs.pop('many', None)
        super().__init__(**kwargs)

10. 通过 钩子函数 丰富验证

局部钩子

通过 validate_字段名(self,接受一个参数), 定义一个钩子函数,丰富对字段的验证。

全局钩子

就是重写serializers.Serializer 中的 validate 方法

    def validate(self, attrs):
        return attrs

11.举例(重新update+钩子函数)

class UserDetailSerializer(serializers.ModelSerializer):
    def update(self, instance, validated_data):
        for attr, value in validated_data.items():
            if attr == "password":
                instance.set_password(value)
            elif attr in ("groups", "user_permissions", "resource_group"):
                getattr(instance, attr).set(value)
            else:
                setattr(instance, attr, value)
        instance.save()
        return instance

    def validate_password(self, password):
        try:
            validate_password(password)
        except ValidationError as msg:
            raise serializers.ValidationError(msg)
        return password

    class Meta:
        model = Users
        fields = "__all__"
        extra_kwargs = {
            "password": {"write_only": True, "required": False},
            "username": {"required": False},
        }

例子来自:https://gitee.com/rtttte/Archery/blob/master/sql_api/serializers.py

 12 serializers.CharField(read_only=True)

read_only=True: 表明该字段仅用于序列化输出,默认为False。如果设置为True,get方式可以看到该字段;而修改时(例如put方式),不需要传该字段。

write_only=True:表明该字段仅用于反序列化,默认为False。如果设置为True,get方式看不到该字段;而修改时(例如put方式),需要传该字段。

还有些其它属性

required :表明该字段在反序列化时必须输入,默认为True;

default: 发序列化时使用的默认值;

allow_null: 表明该字段是否允许传入None,默认False;

validators :该字段使用的验证器;

error_messages:包含错误编号与错误信息的字典;

label:用于HTML展示API页面时,显示的字段名称;

help_text:用于HTML展示API页面时,显示的字段帮助提示信息.

13模型类序列化器--serializers.ModelSerializer

它可让基于 Models 自动创建一个 Serializer 类,其中的字段与模型类字段对应。并且它包含 create() 和 update() 的简单默认实现。

举例

class QueryPrivilegesApplySerializer(serializers.ModelSerializer):
    class Meta:
        model = QueryPrivilegesApply  ##对应models.py 中的指定模型
        fields = "__all__"            ## 指定序列化的字段; "__all__" 所有字段;或者通过("id", "rds_dbinstanceid", "is_enable", ...) 指定想要的字段.
exclude = [xxx,xxx] ## 明确指明排除的字段,注意:fields 和 exclude 属性,在模型类序列化器中只能同时用一个.
read_only_fields ## 指明只读字段;write_only_fields 这个属性被淘汰掉了,后面要通过extra_kwargs属性实现.
extra_kwargs = {"某字段": {"write_only": True}, "某字段": {"required": True}} ##添加或者修改原有的选项参数

14  ModelSerializer 的基本功能和常用方法属性

概说

class ModelSerializer(Serializer):
    """
    A `ModelSerializer` is just a regular `Serializer`, except that:

    * A set of default fields are automatically populated.
    * A set of default validators are automatically populated.
    * Default `.create()` and `.update()` implementations are provided.

    The process of automatically determining a set of serializer fields
    based on the model fields is reasonably complex, but you almost certainly
    don't need to dig into the implementation.

    If the `ModelSerializer` class *doesn't* generate the set of fields that
    you need you should either declare the extra/differing fields explicitly on
    the serializer class, or simply use a `Serializer` class.
    """

常用方法和属性

 15 序列化的对象是多行数据还是单行数据

序列化的对象是多行数据时,参数中一定要有many=True, 这个控制了序列化后对象的类型.

回顾下: Python对象的生成

step 1 对象生成 ----先调用类的__new__方法,生成空对象;类的__new__方法控制对象的生成.

step 2 对象实例化----- 即 对象=类名(XXXX),触发类的__init__() 方法.

我们回头再看序列化.

序列化对象生成,依赖于 BaseSerializer 类的 __new__ 方法

具体代码

    def __new__(cls, *args, **kwargs):
        # We override this method in order to automatically create
        # `ListSerializer` classes instead when `many=True` is set.
        if kwargs.pop('many', False):  ###默认时False, 不传的化,就是False
            return cls.many_init(*args, **kwargs)  ###通过类的绑定方法,这种方式实现
###如果没有传many=True,执行下面代码,正常的对象实例化
return super().__new__(cls, *args, **kwargs)

调用的代码

    @classmethod
    def many_init(cls, *args, **kwargs):
        """
        This method implements the creation of a `ListSerializer` parent
        class when `many=True` is used. You can customize it if you need to
        control which keyword arguments are passed to the parent, and
        which are passed to the child.

        Note that we're over-cautious in passing most arguments to both parent
        and child classes in order to try to cover the general case. If you're
        overriding this method you'll probably want something much simpler, eg:

        @classmethod
        def many_init(cls, *args, **kwargs):
            kwargs['child'] = cls()
            return CustomListSerializer(*args, **kwargs)
        """
        allow_empty = kwargs.pop('allow_empty', None)
        max_length = kwargs.pop('max_length', None)
        min_length = kwargs.pop('min_length', None)
        child_serializer = cls(*args, **kwargs)
        list_kwargs = {
            'child': child_serializer,
        }
        if allow_empty is not None:
            list_kwargs['allow_empty'] = allow_empty
        if max_length is not None:
            list_kwargs['max_length'] = max_length
        if min_length is not None:
            list_kwargs['min_length'] = min_length
        list_kwargs.update({
            key: value for key, value in kwargs.items()
            if key in LIST_SERIALIZER_KWARGS
        })
        meta = getattr(cls, 'Meta', None)
        list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
        return list_serializer_class(*args, **list_kwargs)

 

评论关闭