使用Django Rest Framework的ModelSerializer仅序列化非空字段的方法
实现DRF ModelSerializer仅序列化非空字段的方案
原有修改__init__方案的问题说明
- 序列化器的
__init__方法仅在实例化时执行1次:如果传入的是查询集(many=True场景),序列化器的instance属性是整个查询集,而非单个模型实例,不会为每个实例单独初始化序列化器 - 在
__init__中删除字段会全局影响所有实例的序列化规则,无法针对单个实例的字段值动态调整,完全不符合需求
正确实现方案:重写to_representation方法
to_representation方法会在每个实例序列化时单独调用,是处理单个实例输出的最佳入口,可以完全复用原有ModelSerializer的字段配置,不需要单独定义每个字段。
基础通用版(仅过滤所有假值)
class NonEmptyFieldsModelSerializer(serializers.ModelSerializer): """仅序列化存在真值的字段的ModelSerializer基类""" def to_representation(self, instance): # 先获取默认的序列化结果 ret = super().to_representation(instance) # 过滤掉所有值为假的字段(包括None、空字符串、空列表、0等) return {key: value for key, value in ret.items() if value}
适配0值十进制过滤的优化版
如果需要额外过滤值为0的十进制数(DRF默认转成字符串避免精度损失),可以使用调整后的版本,注意提前引入依赖的copy和re模块:
import copy import re class NonEmptySerializer(serializers.ModelSerializer): def to_representation(self, instance): ret = super().to_representation(instance) non_null_ret = copy.deepcopy(ret) for key in ret.keys(): if not ret[key]: non_null_ret.pop(key) elif isinstance(ret[key], str) and re.fullmatch('[0.]+', ret[key]): # 匹配所有仅由0和.组成的字符串,即值为0的十进制转码结果 non_null_ret.pop(key) return non_null_ret
使用方法
只需要让原有业务序列化器继承上述基类即可,其他代码不需要任何改动:
class OutfitSerializer(NonEmptySerializer): class Meta: model = Outfit fields = '__all__'
视图代码完全保持原有逻辑即可,自动适配单个实例和列表查询的场景。
可选调整说明
如果需要保留特定假值(比如布尔类型的False、合法数值0等),可以自行修改判断逻辑,例如仅过滤None和空字符串:
def to_representation(self, instance): ret = super().to_representation(instance) return { key: value for key, value in ret.items() if value is not None and value != "" }
内容的提问来源于stack exchange,提问作者thorndeux
相关产品推荐
相关产品推荐

