You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何简化Django REST Framework中含重复属性的Serializer类实现?

DRF序列化器复用优化方案

问题背景

在Django REST Framework中,需要为一批具有相同响应结构的视图编写序列化器,为避免重复编写通用字段,当前实现了如下结构:

from rest_framework import serializers
from modelserializers import LogModelSerializer


class GenericValueSerializer(serializers.Serializer):
    message = serializers.CharField(required=True, allow_blank=False, allow_null=False)


class GenericResponseSerializer(serializers.Serializer):
    statusCode = serializers.IntegerField(required=True, allow_null=False)
    statusMessage = serializers.CharField(required=True, allow_blank=False, allow_null=False)


class LoginAppResp(GenericResponseSerializer):
    class LoginAppValue(GenericValueSerializer):
        username = serializers.CharField(required=True, allow_blank=False, allow_null=False)
        token = serializers.CharField(required=True, allow_blank=False, allow_null=False)

    value = LoginAppValue()


class LogsDeviceResp(GenericResponseSerializer):
    class LogsDeviceValue(GenericValueSerializer):
        logs = LogModelSerializer()

    value = LogsDeviceValue(many=True)

期望的响应JSON结构如下:

{
    "statusCode":10,
    "statusMessage":"",
    "value":
    {
        "message":"",
        "api specific field 1":{},
        "api specific field N":{}
    }
}

希望找到更高效的实现方式,减少重复代码。

优化方案

推荐两种更简洁的实现思路,核心是通过动态组合/生成序列化器复用通用逻辑:

方案一:基类+动态生成子类

把通用响应字段封装成基类,通过类方法动态注入具体的value序列化器,避免重复嵌套定义:

from rest_framework import serializers
from modelserializers import LogModelSerializer

class GenericValueSerializer(serializers.Serializer):
    message = serializers.CharField(required=True, allow_blank=False, allow_null=False)

# 通用响应基类
class BaseResponseSerializer(serializers.Serializer):
    statusCode = serializers.IntegerField(required=True, allow_null=False)
    statusMessage = serializers.CharField(required=True, allow_blank=False, allow_null=False)

    @classmethod
    def with_value(cls, value_serializer, many=False):
        """动态生成包含指定value序列化器的响应序列化器"""
        class ResponseSerializer(cls):
            value = value_serializer(many=many)
        return ResponseSerializer

# 定义业务专属的value序列化器
class LoginAppValue(GenericValueSerializer):
    username = serializers.CharField(required=True, allow_blank=False, allow_null=False)
    token = serializers.CharField(required=True, allow_blank=False, allow_null=False)

class LogsDeviceValue(GenericValueSerializer):
    logs = LogModelSerializer()

# 生成最终的响应序列化器
LoginAppResp = BaseResponseSerializer.with_value(LoginAppValue)
LogsDeviceResp = BaseResponseSerializer.with_value(LogsDeviceValue, many=True)

方案二:工具函数快速创建

如果觉得类方法不够直观,可以用工具函数直接生成完整的响应序列化器,代码更轻量化:

from rest_framework import serializers
from modelserializers import LogModelSerializer

class GenericValueSerializer(serializers.Serializer):
    message = serializers.CharField(required=True, allow_blank=False, allow_null=False)

def build_response_serializer(value_serializer, many=False):
    """快速构建响应序列化器的工具函数"""
    class ResponseSerializer(serializers.Serializer):
        statusCode = serializers.IntegerField(required=True, allow_null=False)
        statusMessage = serializers.CharField(required=True, allow_blank=False, allow_null=False)
        value = value_serializer(many=many)
    return ResponseSerializer

# 业务专属value序列化器
class LoginAppValue(GenericValueSerializer):
    username = serializers.CharField(required=True, allow_blank=False, allow_null=False)
    token = serializers.CharField(required=True, allow_blank=False, allow_null=False)

class LogsDeviceValue(GenericValueSerializer):
    logs = LogModelSerializer()

# 生成目标序列化器
LoginAppResp = build_response_serializer(LoginAppValue)
LogsDeviceResp = build_response_serializer(LogsDeviceValue, many=True)

方案优势

  • 通用字段(statusCode、statusMessage、message)只需定义一次,修改时全局生效
  • 业务专属逻辑与通用逻辑完全分离,代码结构更清晰
  • 新增响应序列化器时,只需定义业务字段,调用工具方法即可完成组合,大幅减少重复代码

内容的提问来源于stack exchange,提问作者Farzad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 04:52:35