Django ORM中.count()的正确使用时机
The right time to use .count() in Django ORM
这些是我在我的小项目中的模型
class Tag(models.Model):
name = models.CharField(max_length=200)
class Post(models.Model):
content = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag)
location = models.PointField(null=True, blank=True)
给我一个标签列表(最多3个)。我需要找到每个标签出现在 Post 上的次数。让我们说 ["funny","geek","tech"]
我正在做的是获取标签计数
for tag in tags:
tag_data[tag] = Post.objects.filter(
tags__name=tag,
location__distance_lte=(
pnt, D(km=distance))).count()
然后我使用以下查询获取所有 post 数据。
posts = Post.objects.filter(
tags__name__in=tags,
location__distance_lte=(pnt, D(km=distance)))
我已经在函数结束时循环 posts。
for post in posts:
#some logic
所以我知道那里有标签数据。无需像上面那样进行单独的数据查询来查找计数。但是我发现如果我想在 for 循环中找到标签的计数,我需要在 for 循环中再添加 1 个 for 循环。
for post in posts:
#some logic
for tag in post.tags:
#some logic
所以我的问题是在这里哪个更有效率。像我一样使用 .count() 获取或嵌套 for 循环。
在 Django ORM 中有一个名为 Aggregation 的东西,它使用 .annotate()
和 .aggregate()
方法将您正在寻找的功能添加到查询。 (Docs on Aggregation).
有很多例子可以说明如何获得 Count
、Avg
、Sum
和 more.This 也可以在许多地方完成-对多关系就像你的情况一样。
There's even an example 在与您的情况非常相似的文档中。
For example, if you are retrieving a list of books, you may want to know how many authors contributed to each book. Each Book has a many-to-many relationship with the Author; we want to summarize this relationship for each book in the QuerySet.
要计算 Post
中出现的 Tag
的数量,您只需这样做:
# Add any arguments you want to the filter() to narrow down the Tag query set.
tags = Tags.objects.filter().annotate(Count('post_set'))
# You access it as post_set__count
编辑:
根据您提供的评论,您希望向注释和查询添加条件,以便能够仅对半径内的帖子进行计数。为此,您可以使用 Django 调用的 Conditional Expressions.
借助条件表达式,您可以向 .annotate()
添加条件。
示例:
tags = Tags.objects.filter().annotate(Count(
Case(When(post_set__location="1", then=1), output_field=IntegerField())
))
请阅读文档以找到适合您的情况的正确使用方法。你可以看到 Conditional Expressions with Aggregations.
这些是我在我的小项目中的模型
class Tag(models.Model):
name = models.CharField(max_length=200)
class Post(models.Model):
content = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag)
location = models.PointField(null=True, blank=True)
给我一个标签列表(最多3个)。我需要找到每个标签出现在 Post 上的次数。让我们说 ["funny","geek","tech"]
我正在做的是获取标签计数
for tag in tags:
tag_data[tag] = Post.objects.filter(
tags__name=tag,
location__distance_lte=(
pnt, D(km=distance))).count()
然后我使用以下查询获取所有 post 数据。
posts = Post.objects.filter(
tags__name__in=tags,
location__distance_lte=(pnt, D(km=distance)))
我已经在函数结束时循环 posts。
for post in posts:
#some logic
所以我知道那里有标签数据。无需像上面那样进行单独的数据查询来查找计数。但是我发现如果我想在 for 循环中找到标签的计数,我需要在 for 循环中再添加 1 个 for 循环。
for post in posts:
#some logic
for tag in post.tags:
#some logic
所以我的问题是在这里哪个更有效率。像我一样使用 .count() 获取或嵌套 for 循环。
在 Django ORM 中有一个名为 Aggregation 的东西,它使用 .annotate()
和 .aggregate()
方法将您正在寻找的功能添加到查询。 (Docs on Aggregation).
有很多例子可以说明如何获得 Count
、Avg
、Sum
和 more.This 也可以在许多地方完成-对多关系就像你的情况一样。
There's even an example 在与您的情况非常相似的文档中。
For example, if you are retrieving a list of books, you may want to know how many authors contributed to each book. Each Book has a many-to-many relationship with the Author; we want to summarize this relationship for each book in the QuerySet.
要计算 Post
中出现的 Tag
的数量,您只需这样做:
# Add any arguments you want to the filter() to narrow down the Tag query set.
tags = Tags.objects.filter().annotate(Count('post_set'))
# You access it as post_set__count
编辑:
根据您提供的评论,您希望向注释和查询添加条件,以便能够仅对半径内的帖子进行计数。为此,您可以使用 Django 调用的 Conditional Expressions.
借助条件表达式,您可以向 .annotate()
添加条件。
示例:
tags = Tags.objects.filter().annotate(Count(
Case(When(post_set__location="1", then=1), output_field=IntegerField())
))
请阅读文档以找到适合您的情况的正确使用方法。你可以看到 Conditional Expressions with Aggregations.