如何在Django Rest Framework中向序列化器添加关系值?

dy2hfwbg  于 2023-06-25  发布在  Go
关注(0)|答案(1)|浏览(149)

我想返回数千个结果沿着关系中的一个属性。我尝试在fields数组中包含该值,但得到以下错误:
字段名称checklist__location__latitude对于模型Sighting无效。
是否有方法将latitude值添加到每个瞄准对象?我很谨慎,不想给返回的结果增加太多的开销(它们可能会变得非常大,所以我希望JSON尽可能小),而且我不想在从数据库检索后迭代每个对象来附加值。

wn9m85ua

wn9m85ua1#

您可以使用Django ORM中的annotate()Subquery()来执行此任务。下面是我的代码中的一个例子,它将展示我的意思。它基于其他表中的数据添加多个字段。这些字段可以像往常一样使用DRF进行序列化。

class TaskListAnnotateMixin(GenericAPIView):
    """
    Annotates Task QuerySet with additional fields depending on logged in user:
    - comments_count, category_title, new_comments_count, is_favorite, is_acquainted, author first/second/last name,
      author avatar url.
    """

    def get_queryset(self):
        """
        Annotate QuerySet. Exclude archived tasks and private tasks of other users.
        Apply `order_by()` based on GET parameters.
        """
        task_list = Task.objects.all()

        # Exclude archived tasks
        task_list = task_list.exclude(is_archived=True)

        # Exclude private tasks of other users
        task_list = task_list.exclude(~Q(author=self.request.user) & Q(is_private=True))

        # Count non-archived comments for each task
        task_list = task_list.annotate(
            comments_count=Count("comments", filter=Q(comments__is_archived=False))
        )

        # Add category title
        task_list = task_list.annotate(
            category_title=Subquery(
                TaskCategory.objects.filter(Q(id=OuterRef("category_id"))).values(
                    "title"
                )
            )
        )

        # Add author info directly to comments:
        task_list = task_list.annotate(
            author_last_name=Subquery(
                CustomUser.objects.filter(Q(pk=OuterRef("author_id"))).values(
                    "last_name"
                )
            )
        )
        task_list = task_list.annotate(
            author_first_name=Subquery(
                CustomUser.objects.filter(Q(pk=OuterRef("author_id"))).values(
                    "first_name"
                )
            )
        )
        task_list = task_list.annotate(
            author_second_name=Subquery(
                CustomUser.objects.filter(Q(pk=OuterRef("author_id"))).values(
                    "second_name"
                )
            )
        )

        # ... snip ...

        # Actually define order:
        task_list = task_list.order_by(*order_by_args).select_related("category")

        return task_list

下面是一个关于如何将annotate()创建的字段添加到序列化器的示例:

class TaskSerializer(serializers.ModelSerializer):
    """
    Compact task info for list views (no body, no author name) with additional fields createdb by `annotate()`:
    category_title, comments_count, new_comments_count, is_favorite, is_acquainted (last three depending on current
    user).
    """

    # These fields will be generated by `annotate()` in TaskListAPI.get_queryset():
    category_title = serializers.CharField()
    comments_count = serializers.IntegerField()
    new_comments_count = serializers.IntegerField()
    is_favorite = serializers.BooleanField()
    is_acquainted = serializers.BooleanField()

    class Meta:
        model = Task
        fields = [
            "id",
            "category",
            "category_title",
            "title",
            "is_private",
            "is_archived",
            "attachment",
            "due_date",
            "created",
            "updated",
            "is_completed",
            "completed",
            "comments_count",
            "new_comments_count",
            "is_favorite",
            "is_acquainted",
        ]

相关问题