前因: 在drf的序列化过程中,首先加载资源,然后实例化,在我序列化调用data方法的时候,他才会开始序列化,我们进入看看data的调用
@property
def data(self):
ret = super().data
return ReturnDict(ret, serializer=self)
接着进入父类的data方法中
@property
def data(self):
if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
msg = (
'When a serializer is passed a `data` keyword argument you '
'must call `.is_valid()` before attempting to access the '
'serialized `.data` representation.\n'
'You should either call `.is_valid()` first, '
'or access `.initial_data` instead.'
)
raise AssertionError(msg)
if not hasattr(self, '_data'):
if self.instance is not None and not getattr(self, '_errors', None):
self._data = self.to_representation(self.instance)
elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
self._data = self.to_representation(self.validated_data)
else:
self._data = self.get_initial()
return self._data
也就是这个 他的主要作用在第十四行,to_representation方法,那我们进入这个方法查看一下 我们通过类的继承来父类找他的相关方法,这里不要找错了
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
# We skip `to_representation` for `None` values so that fields do
# not have to explicitly deal with that case.
#
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
这里的fields主要是获取可以序列化的字段(可读字段)包括read_only=True和啥都没写的 在获取的对象列表中,不仅包括普通的常见的charfield,等还包括SerializerMethodField,而这里面有包括了他的field_name,这个方法相当于是使用instance.字段名称,最后的时候调用to_representation,这里我们来看自定以钩子的细节,不讨论charfield等,下面是自定义钩子的源码
def to_representation(self, value):
method = getattr(self.parent, self.method_name)
return method(value)
这个就相当于执行这个方法例如自定义方法的时候会在前面加上个get_,然后是方法名,那么他就会执行这个程序来获取这个值 下面我用一个自定义的钩子方法来实现复合方法,这样既可以触发自己设置的方法,也不会变成必要字段
from collections import OrderedDict
from rest_framework.fields import SkipField
from rest_framework.relations import PKOnlyObject
class NbHookSerializer(object):
def to_representation(self, instance):
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
if hasattr(self, 'nb_%s' % field.field_name):
value = getattr(self, "nb_%s" % field.field_name)(instance)
ret[field.field_name] = value
else:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret