Django count shared manytomany objects 并计算它们
Django count shared manytomany between objects and count them
我有两个模型,分别是 Article 和 Label。它们的简化片段如下:
class Label(models.Model):
name = models.CharField(null=True)
class Article(models.Model):
title = models.CharField(null=True)
labels = models.ManyToManyField(Label, related_name='pieces', blank=True)
查看特定文章时,我想显示与正在查看的文章所应用的标签相似的文章,按与正在阅读的文章共享的标签数量排序(如 "similar articles").
我正在尝试在数据库中执行此操作,但我正在努力寻找一个查询集,该查询集将提供与我在 Python 中所做的相同的功能,方法是从数据库中提取所有文章并执行他们每个人的for循环。下面是我正在尝试执行的无效查询尝试(viewed_article 是正在查看的文章对象):
articles = Article.objects.all()\
.annotate(
tags_count=Article.objects.filter(F('viewed_article.labels')
).count()).order_by(tags_count)
您需要使用 conditional expressions 和一个稍微复杂的查询来实现:
from django.db.models import Case, Count, IntegerField, Sum, When
current_labels = viewed_article.labels.all()
similar_articles = Article.objects.filter(labels__in=current_labels).distinct()\
.annotate(
tag_count=Sum(
Case(
When(labels__in=current_labels, then=1),
default=0, output_field=IntegerField()
)
)
).order_by('-tag_count')
发生的事情是:
获取与当前文章共享任何标签的所有文章。 distinct()
需要清除基础 JOIN
查询返回的重复项。
用条件表达式注释每篇文章。在这里它检查文章是否具有当前文章的每个标签,如果有则将总和加 1。结果是匹配标签的计数。
按匹配标签的数量对结果进行排序。
我有两个模型,分别是 Article 和 Label。它们的简化片段如下:
class Label(models.Model):
name = models.CharField(null=True)
class Article(models.Model):
title = models.CharField(null=True)
labels = models.ManyToManyField(Label, related_name='pieces', blank=True)
查看特定文章时,我想显示与正在查看的文章所应用的标签相似的文章,按与正在阅读的文章共享的标签数量排序(如 "similar articles").
我正在尝试在数据库中执行此操作,但我正在努力寻找一个查询集,该查询集将提供与我在 Python 中所做的相同的功能,方法是从数据库中提取所有文章并执行他们每个人的for循环。下面是我正在尝试执行的无效查询尝试(viewed_article 是正在查看的文章对象):
articles = Article.objects.all()\
.annotate(
tags_count=Article.objects.filter(F('viewed_article.labels')
).count()).order_by(tags_count)
您需要使用 conditional expressions 和一个稍微复杂的查询来实现:
from django.db.models import Case, Count, IntegerField, Sum, When
current_labels = viewed_article.labels.all()
similar_articles = Article.objects.filter(labels__in=current_labels).distinct()\
.annotate(
tag_count=Sum(
Case(
When(labels__in=current_labels, then=1),
default=0, output_field=IntegerField()
)
)
).order_by('-tag_count')
发生的事情是:
获取与当前文章共享任何标签的所有文章。
distinct()
需要清除基础JOIN
查询返回的重复项。用条件表达式注释每篇文章。在这里它检查文章是否具有当前文章的每个标签,如果有则将总和加 1。结果是匹配标签的计数。
按匹配标签的数量对结果进行排序。