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

Django多对多关系序列化:如何将指定字段转为值列表而非字典列表?

问题描述

希望将Django REST Framework中多对多关系的指定字段序列化为值列表,而非包含该字段的字典列表。现有代码及返回结果如下:

现有代码

models.py

from django.db import models

class Bar(models.Model):
    title = models.CharField(max_length=255)

class Foo(models.Model):
    title = models.CharField(max_length=255)
    bars = models.ManyToManyField(Bar, related_name="foos")

serializers.py

from rest_framework.serializers import ModelSerializer 
from .models import Bar, Foo

class BarSerializer(ModelSerializer):
    class Meta:
        model = Bar
        fields = ("title",)

class FooSerializer(ModelSerializer):
    bars = BarSerializer(many=True)

    class Meta:
        model = Foo
        fields = ("title", "bars")

views.py

from rest_framework.generics import ListAPIView
from .serializers import FooSerializer
from .models import Foo

class FooAPIView(ListAPIView):
    queryset = Foo.objects.prefetch_related("bars")
    serializer_class = FooSerializer

当前返回结果

[
    {
        "title": "foo 1",
        "bars": [
            { "title": "bar title 1" },
            { "title": "bar title 2" },
            { "title": "bar title 3" }
        ]
    },
    {
        "title": "foo 2",
        "bars": [
            { "title": "bar title 4" },
            { "title": "bar title 5" },
            { "title": "bar title 6" }
        ]
    },
    {
        "title": "foo 3",
        "bars": [
            { "title": "bar title 7" },
            { "title": "bar title 8" },
            { "title": "bar title 9" }
        ]
    }
]

期望结果

[
  {
    "title": "foo 1",
    "bars": ["bar title 1", "bar title 2", "bar title 3"]
  },
  {
    "title": "foo 2",
    "bars": ["bar title 4", "bar title 5", "bar title 6"]
  },
  {
    "title": "foo 3",
    "bars": ["bar title 7", "bar title 8", "bar title 9"]
  }
]

请问是否有无需重写Django方法的实现方式?


解决方案

当然有,直接使用Django REST Framework提供的序列化字段即可实现,无需修改Django核心方法,以下是几种常用方式:

方法1:使用SlugRelatedField

这是最直接的方案,专门用于序列化关联模型的指定字段为值列表:

from rest_framework.serializers import ModelSerializer, SlugRelatedField
from .models import Foo

class FooSerializer(ModelSerializer):
    bars = SlugRelatedField(many=True, read_only=True, slug_field='title')

    class Meta:
        model = Foo
        fields = ("title", "bars")
  • slug_field指定要序列化的关联模型字段(这里是Bar的title)
  • many=True适配多对多关系
  • read_only=True表示该字段仅用于序列化输出(若需支持反序列化,可移除该参数并配置对应逻辑)

方法2:使用SerializerMethodField

如果需要对字段值做额外处理,这种方式更灵活:

from rest_framework.serializers import ModelSerializer, SerializerMethodField
from .models import Foo

class FooSerializer(ModelSerializer):
    bars = SerializerMethodField()

    def get_bars(self, obj):
        # 直接返回关联Bar对象的title列表
        return [bar.title for bar in obj.bars.all()]

    class Meta:
        model = Foo
        fields = ("title", "bars")

注意:视图中已做prefetch_related("bars"),此处obj.bars.all()不会触发额外数据库查询,性能有保障。

方法3:使用StringRelatedField(需模型定义__str__方法)

如果Bar模型的__str__方法返回title值,可使用该字段:
先修改Bar模型:

class Bar(models.Model):
    title = models.CharField(max_length=255)

    def __str__(self):
        return self.title

再修改序列化器:

from rest_framework.serializers import ModelSerializer, StringRelatedField
from .models import Foo

class FooSerializer(ModelSerializer):
    bars = StringRelatedField(many=True)

    class Meta:
        model = Foo
        fields = ("title", "bars")

以上三种方法均基于DRF现有功能实现,无需改动Django核心方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:22:13