使用具有多个字段的值的聚合来注释查询集

2024-06-23 02:57:15 发布

您现在位置:Python中文网/ 问答频道 /正文

Django注释真的很棒。但是,我不知道如何处理需要几个values()的注释

问题:

我想用相关m2m中的项目计数来注释一个author_queryset。我不知道是否需要使用Subquery,但是:

annotated_queryset = author_queryset.annotate(genre_counts=Subquery(genre_counts))

返回:

SyntaxError: subquery must return only one column

我已经尝试将值强制转换为JSONField以将其返回到一个字段中,希望我可以在其上使用^{},因为我正在使用postgres并需要过滤结果:

subquery = Author.objects.filter(id=OuterRef('pk')).values('id','main_books__genre').annotate(genre_counts=Count('main_books__genre'))

qss = qs.annotate(genre_counts=Subquery(Cast(subquery,JSONField()), output_field=JSONField()))

Yeilds:

AttributeError: 'Cast' object has no attribute 'clone'

我不确定将dict强制转换为JSONField()需要什么。对这些进行过滤有一些很棒的info here。在名为^{}的开发版本中,也有一些专为博士后准备的东西,它看起来可以解决这个问题。然而,我不能使用这个功能,直到它在一个稳定的版本

期望结果

我想注释,以便根据注释进行过滤,如下所示:

annotated_queryset.filter(genre_counts__scifi__gte=5)

细部

我可以使用dunders获得相关字段,然后像这样计数:

# get all the authors with Virginia in their name
author_queryset = Author.objects.filter(name__icontains='Virginia')
author_queryset.count()
# returns: 21

# aggregate the book counts by genre in the Book m2m model
genre_counts = author_queryset.values('id','main_books__genre').annotate(genre_counts=Count('main_books__genre'))
genre_counts.count()

# returns: 25

这是因为queryset中的每个Author对象可以返回多个类型计数。在这个特定的例子中,有一位作者拥有4种不同类型的书籍:

举例说明:

...
{'id': 'authorid:0054f04', 'main_books__genre': 'scifi', 'genre_counts': 1}
{'id': 'authorid:c245457', 'main_books__genre': 'fantasy', 'genre_counts': 4}
{'id': 'authorid:a129a73', 'main_books__genre': None, 'genre_counts': 0}
{'id': 'authorid:f41f14b', 'main_books__genre': 'mystery', 'genre_counts': 16}
{'id': 'authorid:f41f14b', 'main_books__genre': 'romance', 'genre_counts': 1}
{'id': 'authorid:f41f14b', 'main_books__genre': 'scifi', 'genre_counts': 9}
{'id': 'authorid:f41f14b', 'main_books__genre': 'fantasy', 'genre_counts': 3}
...

还有一个作家有两个,其余的都有一个流派。这是25个值

希望这对某人有意义!我相信有一种方法可以在不等待上述功能的情况下正确处理此问题


Tags: idmainbooksauthorqueryset计数valuesjsonfield
1条回答
网友
1楼 · 发布于 2024-06-23 02:57:15

您希望使用.annotate(而不使用Subquery,因为您发现,这需要返回一个值。您应该能够跨越第一个注释的计数表达式中的所有关系

不幸的是,Django不支持您当前使用genre_counts__scifi_gt=5查找的内容。您可以对其进行构造,以便使用传递给它的筛选器进行计数

selected_genre = 'scifi'
annotated_queryset = author_queryset.annotate(
    genre_count=Count("main_books__genre", filter=Q(genre=selected_genre))
).filter(genre_count__gte=5)

要获得完整的细分,最好返回细分并在应用程序中进行最终聚合,如您在问题中所示

相关问题 更多 >

    热门问题