Django.rest_framework:如何序列化一对多到多对多?

14 投票
1 回答
8252 浏览
提问于 2025-04-18 13:24

我在使用Django进行序列化时遇到了一些麻烦。

我有三个模型,分别是学校、教室和桌子(这只是个例子)。每个学校有多个教室,每个教室又有多个桌子。

这些类和它们之间的关系大致是这样的:

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

class Room(models.Model):
    name = models.CharField()
    school_id = models.ForeignKey(School)

class Desk(models.Model):
    row = models.IntegerField()
    col = models.IntegerField()
    room_id = models.ForeignKey(Room)

我想要能够序列化一个学校的列表,每个学校里面直接包含所有的桌子。

我目前最接近的做法是在我的serialize.py文件里写了三个序列化器:

class DeskSerializer(serializers.ModelSerializer):
    class Meta:
        field = (row, col,)

class RoomSerializer(serializers.ModelSerializer):

    desks = DeskSerializer(source='desk_set', many=True)
    class Meta:
        field = (desks,)

class SchoolSerializer(serializers.ModelSerializer):

    rooms = RoomSerializer(source='room_set', many=True)
    class Meta:
        field = (name, rooms,)

这样返回的是一个包含教室列表的学校列表,而我想要的是一个包含桌子列表的学校列表。

在学校的序列化器中,我应该使用哪个源来直接返回桌子呢?像是source='room_set.desk_set'这样?或者我应该使用一个transform_函数?

另外,帖子里的代码是从头写的,请忽略可能的语法错误。

1 个回答

21

如果我理解得没错,你想让 SchoolSerializer 返回一个嵌套结构,深度为两层,但要跳过中间的模型。为了做到这一点,我建议在你的 School 模型里创建一个方法,用来获取 Desk 实例:

class School(models.Model):
    ...

    def get_desks(self):
        rooms = Room.objects.filter(school=self)
        desks = Desk.objects.filter(room__in=rooms)
        return desks

然后,在你的 SchoolSerializer 中加入一个字段,使用这个方法,并通过你的 DeskSerializer 来渲染返回的实例:

class SchoolSerializer(serializers.ModelSerializer):
    ...
    desks = DeskSerializer(
        source='get_desks',
        read_only=True
    )

    class Meta:
        field = (name, desks)

理解这个过程的关键是,作为 source 参数值的模型方法必须简单地返回那个序列化器模型的实例。序列化器会接手,按照你在那个序列化器中定义的方式来渲染对象(在这个例子中是 DeskSerializer)。

希望这对你有帮助。

撰写回答