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']