使用具有多个字段的值的聚合来注释查询集
Annotating a queryset using aggregations of values with more than one field
Django 注释真的很棒。但是我不知道如何处理需要多个 values()
的注释。
问题:
我想用相关 m2m 中的项目计数来注释 author_queryset
。我不知道我是否需要使用 Subquery
,但是:
annotated_queryset = author_queryset.annotate(genre_counts=Subquery(genre_counts))
Returns:
SyntaxError: subquery must return only one column
我已经尝试将值转换为 JSONField
以将其返回到一个字段中,希望我可以在其上使用 JSONBagg
因为我正在使用 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()))
产量:
AttributeError: 'Cast' object has no attribute 'clone'
我不确定我需要什么才能将字典转换为 JSONField()。有一些很棒的 info here about filtering on these. There's also something for postgres coming soon in the development version called ArraySubQuery()
可以解决这个问题。但是,在稳定版本发布之前,我无法使用此功能。
想要的结果
我想添加注释,这样我就可以根据注释进行过滤,如下所示:
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
这是因为可以为查询集中的每个作者对象返回多个流派计数。在此特定示例中,有一位作者拥有 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}
...
还有一位作者有 2 个,其余各有一个流派。这是25个值。
希望这对某人有意义!我确信有一种方法可以正确处理此问题,而无需等待上述功能。
您想使用不带 Subquery
的 .annotate(
,因为如您所见,这需要 return 一个值。您应该能够跨越第一个注释的计数表达式中的所有关系。
很遗憾,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)
要获得完整的细分,您最好 return 进行细分并在应用程序中进行最终聚合,如您在问题中所示。
Django 注释真的很棒。但是我不知道如何处理需要多个 values()
的注释。
问题:
我想用相关 m2m 中的项目计数来注释 author_queryset
。我不知道我是否需要使用 Subquery
,但是:
annotated_queryset = author_queryset.annotate(genre_counts=Subquery(genre_counts))
Returns:
SyntaxError: subquery must return only one column
我已经尝试将值转换为 JSONField
以将其返回到一个字段中,希望我可以在其上使用 JSONBagg
因为我正在使用 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()))
产量:
AttributeError: 'Cast' object has no attribute 'clone'
我不确定我需要什么才能将字典转换为 JSONField()。有一些很棒的 info here about filtering on these. There's also something for postgres coming soon in the development version called ArraySubQuery()
可以解决这个问题。但是,在稳定版本发布之前,我无法使用此功能。
想要的结果
我想添加注释,这样我就可以根据注释进行过滤,如下所示:
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
这是因为可以为查询集中的每个作者对象返回多个流派计数。在此特定示例中,有一位作者拥有 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}
...
还有一位作者有 2 个,其余各有一个流派。这是25个值。
希望这对某人有意义!我确信有一种方法可以正确处理此问题,而无需等待上述功能。
您想使用不带 Subquery
的 .annotate(
,因为如您所见,这需要 return 一个值。您应该能够跨越第一个注释的计数表达式中的所有关系。
很遗憾,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)
要获得完整的细分,您最好 return 进行细分并在应用程序中进行最终聚合,如您在问题中所示。