Django序列化类的小方法

Serializer类中的get_initial属性

在反序列化的过程中,我们首先通过产生一个序列化对象.is_valid()去进行数据的校验,那么在此之前,我们使用序列化对象.initial_data拿到原始数据,进行处理,我们可以在这个数据里面进行序列化之前的对数据进行操作,比如拿到一些校验字段没有填写的数据,我们直接进行校验,然后放入self.validated_data中,这样该数据就会直接被放到校验后的数据中

Serializer类中的`validated_data'就是校验后的数据,我们可以通过initial_data与validated_data进行数据校验的一些跳转,以及自己进行数据的校验

使用该方法需要注意,这个字段在序列化类中不要写,否则还会再走一遍序列化的校验,会存在字段覆盖的风险

class BookView(GenericViewSet, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def create(self, request, *args, **kwargs):
        ser = self.get_serializer_class()
        # 传入反序列化的数据
        ser_obj = ser(data=request.data)
        # 可以通过该属性拿到反序列化的传入的原始数据,进行数据的获取
        print(ser_obj.initial_data, '序列化之前的数据')
        # {'name': '西游记1', 'price': '123', 'addr': '北京'} 反序列化校验之前的数据
        
        
        # 这里拿到addr,放到校验后的数据中
        addr = ser_obj.initial_data.get('addr')
        
        print(addr)  # 北京
        ser_obj.is_valid(raise_exception=True)
        # is_valid之后证明数据走完字段校验以及局部、全局钩子,我们可以将之前没有反序列化的数据放到校验以后得字典中
        ser_obj.validated_data['addr'] = addr
        
        print(ser_obj.validated_data, '校验以后得数据')
        # OrderedDict([('name', '西游记1'), ('price', '123'), ('addr', '北京')]) 校验以后得数据
        
        # save方法会直接进行数据的保存
        ser_obj.save()        
        return Response('成功')


# 序列化类中,我们并没有进行这个字段的校验
from rest_framework.serializers import ModelSerializer
from .models import Book


class BookSerializer(ModelSerializer):
    class Meta:
        model = Book
        fields = ['name', 'price']

字段:serializers.SerializerMethodField

我们使用这个字段的时候,要注意该字段只会在不改变read_only=False的情况下,该字段只有一个可读的属性,我们可以验证一下
class BookView(GenericViewSet, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def create(self, request, *args, **kwargs):
        ser = self.get_serializer_class()
        ser_obj = ser(data=request.data)
        ser_obj.is_valid(raise_exception=True)
        print(ser_obj.validated_data, '校验以后得数据')
        # OrderedDict([('name', '西游记1'), ('price', '123')]) 校验以后得数据
        # 校验后的字段没有addr字段,证明反序列化没有走这个字段
        ser_obj.save()
        return Response('成功')


# 序列化类
class BookSerializer(ModelSerializer):
    addr = serializers.SerializerMethodField()
    class Meta:
        model = Book
        fields = ['name', 'price','addr']

从上面我们可以看到SerializerMethodField这个字段只有读的属性,并不会有写的属性,如果我们需要进行一个字段进行可读和可写的话,需要我们自己自定义,如下

class BookView(GenericViewSet, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def create(self, request, *args, **kwargs):
        ser = self.get_serializer_class()
        ser_obj = ser(data=request.data)
        ser_obj.is_valid(raise_exception=True)
        print(ser_obj.validated_data, '校验以后得数据')
        # OrderedDict([('name', '西游记1'), ('price', '123'), ('addr', '北京')]) 校验以后得数据

        # save方法会直接进行数据的保存
        ser_obj.save()
        print(ser_obj.data)
        # {'name': '西游记1', 'price': '123', 'addr': '北京'}
        return Response('成功')


class ReadWriteSerializerMethodField(serializers.SerializerMethodField):
    def __init__(self, method_name=None, **kwargs):
        self.method_name = method_name
        self.read_only = False
        super(serializers.SerializerMethodField, self).__init__(**kwargs)

    def to_internal_value(self, data):
        """
        Deserialize the field's value from the given data.
        """
        method = getattr(self.parent, self.method_name)
        return method(data)

    def to_representation(self, value):
        """
        Serialize the field's value.
        """
        method = getattr(self.parent, self.method_name)
        return method(value)


class BookSerializer(ModelSerializer):
    addr = ReadWriteSerializerMethodField()

    class Meta:
        model = Book
        fields = ['name', 'price', 'addr']

    def get_addr(self, field):
        # 返回的是序列化与反序列化所要的字段
        print(field, 'obj指的是我们要进行序列化和反序列化的数据')
        return field

或者采用另外的一种方法,这样可拓展性更高一点

class ReadWriteSerializerMethodField(SerializerMethodField):
    """
    支持可读写的SerializerMethodField
    可实现Model字段和Serializer字段更加灵活地解绑
    通过实现get_xxxfield方法,实现从Model的某个字段读值映射到Serializer对应字段
    通过实现set_xxxfield方法,实现从Serializer字段回填值到Model对应字段
    """

    def __init__(self, method_name=None, write_method_name=None, **kwargs):
        self.method_name = method_name
        self.write_method_name = write_method_name
        kwargs["source"] = "*"
        super(SerializerMethodField, self).__init__(**kwargs)

    def bind(self, field_name, parent):
        # 绑定读函数 get_{field_name} 和写函数 set_{field_name}
        default_method_name = f"get_{field_name}"
        default_write_method_name = f"set_{field_name}"

        if self.method_name is None:
            self.method_name = default_method_name
        if self.write_method_name is None:
            self.write_method_name = default_write_method_name
        super(SerializerMethodField, self).bind(field_name, parent)

    def to_representation(self, value):
        # 读取过程hook
        method = getattr(self.parent, self.method_name)
        return method(value)

    def to_internal_value(self, data):
        # 写入过程hook
        method = getattr(self.parent, self.write_method_name)
        return method(data)

class BookSerializer(ModelSerializer):
    addr = ReadWriteSerializerMethodField()

    def get_addr(self, obj):
        # 序列化会走这里,所以可以定制序列化格式
        print(obj, '这是什么obj')
        return obj.addr

    def set_addr(self, data):
        # 先走这里进行反序列化
        print(data, 'data是什么')
        return {'addr': data}

    class Meta:
        model = Book
        fields = ['name', 'price', 'addr']

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值