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
相关产品推荐
相关产品推荐

