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",
]
1条答案
按热度按时间wn9m85ua1#
您可以使用Django ORM中的
annotate()
和Subquery()
来执行此任务。下面是我的代码中的一个例子,它将展示我的意思。它基于其他表中的数据添加多个字段。这些字段可以像往常一样使用DRF进行序列化。下面是一个关于如何将
annotate()
创建的字段添加到序列化器的示例: