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

在DRF中使用Serializer同时获取StringRelatedField与PrimaryKeyRelatedField

别担心,新手遇到这种摸不着头绪的问题太正常啦!我来帮你搞定在DRF序列化器里同时拿到关联字段的主键和显示名称的需求~

先结合你给出的模型代码,给你两种常用的解决方案:

方法一:用嵌套序列化器(推荐,更规范)

这种方式适合需要重复使用关联字段序列化逻辑的场景,先给关联的Materia模型写一个极简的序列化器,只返回你需要的主键和名称字段:

class MateriaSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()  # 这里替换成Materia模型里实际用来显示的字段,比如你定义的__str__对应的字段

然后在TemaPai的序列化器里直接嵌套这个序列化器,处理多对多关系:

class TemaPaiSerializer(serializers.ModelSerializer):
    # 多对多关系要加上many=True
    disciplines = MateriaSerializer(many=True, read_only=True)

    class Meta:
        model = TemaPai
        fields = ['id', 'subject', 'disciplines']

如果是处理TemaPaiOrdem里的外键关联(比如discipline字段),同样套用这个逻辑:

class TemaPaiOrdemSerializer(serializers.ModelSerializer):
    # 嵌套subject的信息
    subject = serializers.SerializerMethodField()
    # 嵌套discipline的信息
    discipline = MateriaSerializer(read_only=True)

    def get_subject(self, obj):
        # 直接用TemaPai的__str__方法拿到显示文本,同时返回主键
        return {
            'id': obj.subject.id,
            'name': str(obj.subject)
        }

    class Meta:
        model = TemaPaiOrdem
        fields = ['id', 'subject', 'discipline']

方法二:用SerializerMethodField(灵活快捷)

如果只是临时需要构造返回格式,不想单独写嵌套序列化器,可以直接用SerializerMethodField自定义返回内容:

class TemaPaiSerializer(serializers.ModelSerializer):
    disciplines = serializers.SerializerMethodField()

    def get_disciplines(self, obj):
        # 遍历所有关联的discipline,构造包含主键和名称的字典列表
        return [
            {'id': dis.id, 'name': str(dis)} 
            for dis in obj.disciplines.all()
        ]

    class Meta:
        model = TemaPai
        fields = ['id', 'subject', 'disciplines']

兼顾读写的场景

如果你的序列化器需要支持写入操作(比如创建/更新TemaPai时传入discipline的主键),可以把主键字段设为只写,显示字段设为只读:

class TemaPaiSerializer(serializers.ModelSerializer):
    # 写入时传主键列表,只写
    discipline_ids = serializers.PrimaryKeyRelatedField(
        queryset=Materia.objects.all(),
        many=True,
        source='disciplines',
        write_only=True
    )
    # 读取时返回带名称的详细信息,只读
    disciplines = serializers.SerializerMethodField(read_only=True)

    def get_disciplines(self, obj):
        return [{'id': dis.id, 'name': str(dis)} for dis in obj.disciplines.all()]

    class Meta:
        model = TemaPai
        fields = ['id', 'subject', 'discipline_ids', 'disciplines']

这样写接口的时候传discipline_ids(比如[1,3,5]),读接口的时候就能拿到包含主键和名称的disciplines列表啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:06:40