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

在Django Rest Framework中如何序列化继承类而非基类?

背景

models.py

假设我有一个名为**"Base"**的通用Django模型类,用于统一所有继承它的类:

class Base(models.Model):
    name = models.CharField(...)

    belongs_to = models.ForeignKey(
        'self', on_delete=models.PROTECT, blank=True, null=True
    )

还有继承自**"Base"的"Company"**类:

class Company(Base):
    pass  # 仅继承Base的属性

同样继承自**"Base"但拥有role属性的"Manager"**类:

class Manager(Base):
    role = models.ForeignKey(Roles, on_delete=models.CASCADE ...)

以及继承自**"Base"且拥有job属性的"Worker"**类:

class Worker(Base):
    job = models.ForeignKey(Jobs, on_delete=models.CASCADE ...)

实例化示例

以下是这些类的实例化示例:

Company.objects.create(name='Company1', 
                       belongs_to=None) # 同时会创建ID为1的Base对象


Manager.objects.create(name='Manager1', 
                       belongs_to=1, 
                       role=1)  # 创建Manager对象并关联到Company

Worker.objects.create(name='Worker1', 
                      belongs_to=2, job=1) # 表示Worker归属于Manager对象

设计思路是Worker也可以不归属Manager,直接归属于Company,例如:

Worker.objects.create(name='Worker34', 
                      belongs_to=1, 
                      job=1) # 表示Worker归属于Company对象
Django Rest Framework问题总结

我正在使用serializer.ModelSerializer(为保持实现简单高效),通过Meta中的depth参数实现嵌套对象:

serializer.py

class WorkerSerializer(serializers.ModelSerializer):

    class Meta:
        model = Worker
        fields = '__all__'
        depth = 3

但由于belongs_to是Base类的属性,它仅返回Base类中包含的信息,示例如下:

{
        "id": 3,
        "name": "Worker1",
        "belongs_to": {
            "id": 2,
            "name": "Manager1",
            ****此处我希望显示Manager对象的额外信息****
            "belongs_to": {
                "id": 1,
                "name": "Company1",
            }
        },
    },

在这个示例中,我需要获取Manager关联的Roles表中的'roles'属性(示例中已省略)。

是否可以指定Serializer先判断belongs_to指向的是哪个子类,而非仅序列化基类的属性?这是否可行?如果可行,该如何实现?


解决方案

要实现根据belongs_to指向的子类类型动态序列化,可通过以下几种方式实现:

方法1:自定义序列化字段(推荐)

创建自定义字段,序列化时判断关联对象的实际类型,选择对应序列化器处理。

步骤1:为每个子类创建序列化器

from rest_framework import serializers
from .models import Base, Company, Manager, Worker, Roles, Jobs

class CompanySerializer(serializers.ModelSerializer):
    class Meta:
        model = Company
        fields = '__all__'
        depth = 2

class ManagerSerializer(serializers.ModelSerializer):
    role = serializers.StringRelatedField() # 也可根据需求使用RolesSerializer
    class Meta:
        model = Manager
        fields = '__all__'
        depth = 2

class BaseRelatedField(serializers.RelatedField):
    def to_representation(self, value):
        # 判断对象实际类型
        if isinstance(value, Manager):
            return ManagerSerializer(value).data
        elif isinstance(value, Company):
            return CompanySerializer(value).data
        elif isinstance(value, Base):
            # 处理纯Base实例(若存在)
            return {'id': value.id, 'name': value.name}
        return super().to_representation(value)

步骤2:修改WorkerSerializer使用自定义字段

class WorkerSerializer(serializers.ModelSerializer):
    belongs_to = BaseRelatedField(read_only=True)

    class Meta:
        model = Worker
        fields = '__all__'

此时belongs_to指向Manager时会自动序列化role等额外字段;指向Company时则序列化Company的全部字段。

方法2:利用Django ContentType框架

如果模型使用多表继承(Django默认对非抽象基类使用多表继承),可通过ContentType判断对象类型:

from django.contrib.contenttypes.models import ContentType

class DynamicBelongsToField(serializers.SerializerMethodField):
    def to_representation(self, obj):
        # 获取关联对象的ContentType
        ct = ContentType.objects.get_for_model(obj.belongs_to)
        model_class = ct.model_class()
        
        # 根据模型类选择序列化器
        if model_class == Manager:
            return ManagerSerializer(obj.belongs_to).data
        elif model_class == Company:
            return CompanySerializer(obj.belongs_to).data
        else:
            return {'id': obj.belongs_to.id, 'name': obj.belongs_to.name}

class WorkerSerializer(serializers.ModelSerializer):
    belongs_to = DynamicBelongsToField()

    class Meta:
        model = Worker
        fields = '__all__'

该方法适合需灵活判断类型的场景,但依赖Django的ContentType框架。

注意事项

  • 若Base是抽象基类(添加abstract = True),Django不为Base创建单独表,所有子类字段存于各自表中,此时可直接用方法1的类型判断。
  • 避免同时使用depth参数和自定义序列化字段,可能导致序列化结果冲突。
  • 若需支持反序列化(POST/PUT请求),需在自定义字段中实现to_internal_value方法,处理不同类型的输入数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:15:38