如何在Django Rest Framework中序列化三个具有多对多关系的模型

Posted

技术标签:

【中文标题】如何在Django Rest Framework中序列化三个具有多对多关系的模型【英文标题】:How to serialize three models with many to many relationships in Django Rest Framework 【发布时间】:2020-12-23 20:37:13 【问题描述】:

我有三个基本模型:

class User(models.Model):
    displayName= models.CharField(max_length=128)

class Cell(models.Model):
    title = models.CharField(max_length=128)

class List(models.Model):
    title = models.CharField(max_length=128)

以及它们之间的三个多对多关系:

class UserCell(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE
    )
    cell = models.ForeignKey(
        Cell,
        on_delete=models.CASCADE
    )
    value = models.SmallIntegerField()

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['user', 'cell'],
                name='unique_UserCell'
            )
        ]

class UserList(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE
    )
    target_list = models.ForeignKey(
        List,
        on_delete=models.CASCADE
    )
    last_updated = models.DateTimeField(default=timezone.now)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['user', 'target_list'],
                name='unique_UserList'
            )
        ]

class CellAssignment(models.Model):
    target_list = models.ForeignKey(
        List,
        on_delete=models.CASCADE
    )
    cell = models.ForeignKey(
        Cell,
        on_delete=models.CASCADE
    )
    idx = models.SmallIntegerField()

    class Meta:
        ordering = ['idx']
        constraints = [
            models.UniqueConstraint(
                fields=['target_list', 'idx'],
                name='unique_cellAssignment'
            )
        ]

我的视图有一个 List.id 和一个 User.id,我想以以下格式或类似格式返回数据:

"List.id": 2, "List.title": "The Big List of Cells", "List.created_date": "2020-10-02T18:14:02Z",  "cells": ["target_list.id": 2, "Cell.id": 6, "CellAssignment.idx": 0, "Cell.title": "The first cell", "UserCell.value": 4, "target_list.id": 2, "Cell.id": 12, "CellAssignment.idx": 1, "Cell.title": "This is the second cell and so on", "UserCell.value": 9, ...]

是否可以通过嵌套序列化程序来做到这一点,或者我应该单独查询关系并在视图中加入数据?任何有关这两种方法之间性能差异的信息将不胜感激。

编辑 (12/24)。当前的序列化器:

class UserCellSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserCell
        fields = '__all__'

class CellSerializer(serializers.ModelSerializer):
    class Meta:
        model = Cell
        fields = ['id', 'title']

class CellAssignmentSerializer(serializers.ModelSerializer):
    cell_title = serializers.ReadOnlyField(source='cell.title')
    cell_value = serializers.ReadOnlyField(source='cell.user_cell.value')

    class Meta:
        model = CellAssignment
        #target_list and cell are not strictly needed below, as of now. good for debug tho.
        fields = ['target_list', 'idx', 'alt_title', 'cell_title', 'cell_value']

class ListSerializer(serializers.ModelSerializer):
    cell_details = CellAssignmentSerializer(read_only=True, many=True)

    class Meta:
        model = List
        fields = ['id', 'title', 'created_date', 'cell_details']

【问题讨论】:

【参考方案1】:

https://www.django-rest-framework.org/api-guide/relations/#nested-relationships

你可以制作嵌套序列化器。

    为模型制作每个序列化程序。 使所有序列化程序嵌套。

首先,只需制作每个序列化程序,然后将它们全部合并为嵌套。 它应该可以工作。

更新,

cell = models.ForeignKey(
        Cell,
        on_delete=models.CASCADE,
        related_name="user_cells"
    )

然后,您可以像访问单元格一样访问 user_cell

  cell_instance.user_cells.all()

或任何你想要的。

【讨论】:

感谢您的回复山姆。我确实知道我可以制作嵌套序列化程序。我已经将列表字段与单元格对象列表一起序列化。我坚持让 UserCell.value 与每个单元格协调。我还想知道,如果通过 id 手动连接表似乎更容易(就像通常使用关系 SQL 所做的那样),那么通过复杂的模型/序列化程序过程是否值得付出努力。 您可以使用反向foreign_key获取数据。使用related_name它可以让你得到UserCell数据。 是的,我认为related_name 将是关键。我已将它添加到单元格 ForeignKey 上的 UserCell:related_name='user_cell'。对于以下序列化程序,显示了 cell_title 但未显示 cell_value:class CellAssignmentSerializer(serializers.ModelSerializer): cell_title = serializers.ReadOnlyField(source='cell.title') cell_value = serializers.ReadOnlyField(source='cell.user_cell.value') 似乎无法深入到相邻关系? 可以在调用 CellAssignmentSerializer 之前添加视图代码吗? 视图现在没有做任何工作,单元格分配实际上嵌套在 ListSerializer 中,many=True。所以我只是通过 id 和targetList = List.objects.get(pk=pk) 获取我请求的列表,然后将其交给 ListSerializer:list_serializer = ListSerializer(targetList)

以上是关于如何在Django Rest Framework中序列化三个具有多对多关系的模型的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django-rest-framework 中为 API 使用 TokenAuthentication

如何在 Django Rest Framework 中处理并行请求?

如何让 django-rest-framework-jwt 在注册时返回令牌?

如何在 Django 的单个 API 中获取访问令牌和刷新令牌(rest_framework_jwt)

如何修复在 Django Rest Framework 中使用 REST API 登录时出现的 CSRF 错误?

如何在 Django Rest Framework 中编写涉及两个模型的业务逻辑