SerializerMethodField()
用于只读字段,通过序列化器类型的父类,会自动调用函数名为 get_{filed_name} 的函数,对返回的结果进行处理。
使用方式:
class ExampleSerializer(self):
extra_info = SerializerMethodField()
def get_extra_info(self, obj):
return ... # Calculate some data to return.
# 实战代码来自 @大江狗,略微经过修改
class ArticleSerializers(serializers.ModelSerializer):
author = serializers.HiddenField(default=serializers.CurrentUserDefault())
cn_status = serializers.SerializerMethodField()
class Meta:
model = Article
fields = '__all__'
read_only_fields = ('id', 'create_date')
def get_cn_status(self, obj):
status_dict = {
'p': '已发表', 'd': '草稿'}
if status_dict.get(obj.status):
return status_dict[obj.status]
return '未知'
# 也可以编写任意名字的函数,在 SerializerMethodField 实例化时以 method_name 传入字符串形式的函数名(不推荐)
class ArticleSerializers(serializers.ModelSerializer):
author = serializers.HiddenField(default=serializers.CurrentUserDefault())
# 实例化时传入自定义的函数名
cn_status = serializers.SerializerMethodField(method_name='add_cn_status')
class Meta:
model = Article
fields = '__all__'
read_only_fields = ('id', 'create_date')
# 自定义一个函数名
def add_cn_status(self, obj):
status_dict = {
'p': '已发表', 'd': '草稿'}
if status_dict.get(obj.status):
return status_dict[obj.status]
return '未知'
通过 SerializerMethodField 类,我们对 status 这一参数进行了二次加工,增加了中文显示类,注意这里的 cn_status 只读,无法进行修改和增加。
代码分析
class SerializerMethodField(Field):
"""
该类是 Field 的子类
"""
def __init__(self, method_name=None, **kwargs):
# 初始化时接受 method_name 这一参数的值作为返回前二次处理的函数
self.method_name = method_name
# 设置要查找的模型字段为所有字段
kwargs['source'] = '*'
# 默认该字段为空字段
kwargs['read_only'] = True
super().__init__(**kwargs)
def bind(self, field_name, parent):
# The method name defaults to `get_{field_name}`.
# 如果初始化时没有传入对应 methhod_name,会自动将 get_{field_name} 这一形式的函数作为二次处理函数进行绑定
if self.method_name is None:
self.method_name = 'get_{field_name}'.format(field_name=field_name)
super().bind(field_name, parent)
def to_representation(self, value):
method = getattr(self.parent, self.method_name)
return method(value)
补充内容
通过查阅官方文档我们可以看到,在使用模型作为序列化对象时需要提供 source 的默认值,方便框架定位具体需要展示的字段。但在 SerializerMethodField 中不确定我们会使用到模型中的哪个字段进行二次加工,所以传入 * 表示整个模型对象都需要传入。