我有以下型号。
class Tag(models.Model):
name = models.CharField(max_length=30)
# and other fields ...
class Book(models.Model):
name = models.CharField(max_length=140)
tags = models.ManyToManyField(Tag, blank=True)
# and other fields
class Article(models.Model):
name = models.CharField(max_length=140)
tags = models.ManyToManyField(Tag, blank=True)
很少有其他模型具有“ ManyToMany”字段的标签。我想获取最常用的标签对象的列表。我尝试从每个模型中过滤最常用的标签,然后从每个模型中获取前十名,并将它们与其他前十名组合。我认为应该从“标签”模型本身中做些什么来找到最常用的标签实例。
除了我的方法之外,有什么方法可以找到最常用的标签实例?任何帮助将不胜感激。
答案 0 :(得分:0)
书籍模型中10个最常用标签的列表:
tags_of_book = Tag.objects.all().annotate(num_book = Count('book')).order_by('-num_book')[:10]
文章模型中10个最常用标签的列表:
tags_of_article = Tag.objects.all().annotate(num_article = Count('article')).order_by('-num_article')[:10]
答案 1 :(得分:0)
您可以使用annotate()
使标签按在Article
中使用的时间排序(对Book
可以这样做):
Tag.objects.all().annotate(
nb_articles=Count("article_set"),
).order_by("-nb_articles")
但是,要在Article
和Book
中获得最常用的标签,可能需要更多查询或可能使用Subqueries(请参阅doc)的更高级的
答案 2 :(得分:0)
假设您要让Book
的前10个标签使用,然后可以这样查询:
from django.db.models import Count
Tag.objects.annotate(
nused=Count('book')
).order_by('-nused')[:10]
因此,我们根据每个标签的相关书籍数量在数据库中查询Tag
所订购的商品。
我们可以使用多个计数,但是通过在一个查询中使用它们,通常会产生昂贵的查询:在这种情况下,您将JOIN
使用所有这些相关模型,因此,时间复杂度查询通常会在模型数量上呈指数增长。尽管有些数据库管理员可能发现这些子查询是“ 独立”子查询,但根据我的经验,流行的子查询通常不会。因此,我们最好在这里使用多个查询:每个相关模型一个。
因此,现在我们首先需要找出相关模型。幸运的是,Django为此提供了一些实用程序功能。每个模型类都有一个._meta
对象,该对象存储有关模型的信息。这些属性之一是.fields_map
,它返回一个字典,该字典将关系的名称映射到关系对象。
我们可以使用它来枚举关系,因此对于每个关系都使用查询:
from collections import Counter
from django.db.models import Count
cntr = Counter()
for relation in Tag._meta.fields_map:
cntr.update(
{
tg: tg.nr
for tg in Tag.objects.annotate(nr=Count(relation)).order_by('nr')[:10]
}
)
最后,我们将有一个Counter
,其中包含这些标签的总出现次数。但是请注意,由于我们每次都将数字限制为10。
然后我们可以通过从柜台获得最常用的标签来获取最受欢迎的标签:
from operator import itemgetter
my_tags = map(itemgetter(0), ca.most_common(10))
.most_common(10)
将生成前10个标记(通过将每种关系中最常见的标记求和),并返回2元组的列表:每个元组都包含Tag
实例,以及使用次数。通过使用map(itemgetter(0), ...)
,我们仅获得Tag
。但是您可能也对数字感兴趣。
这不是不是,这意味着我们本身拥有最频繁的标签。确实,假设某个标签是Book
和Article
的第11个最受欢迎的标签,那么它仍然可能是整体上最受欢迎的标签,因为有可能排名前10位Book
和Article
完全不同。还是一个小例子:
Top Books Top Articles
1. A (10) 1. D (12)
2. B (8) 2. E (8)
3. C (7) 3. C (7)
如果使用上述方法生成前2名,则我们将错过实际发生次数最多(共C
次)的14
。
我们可以通过简单地始终计数所有Tag
来解决此问题,从而消除[:10]
的限制:
from collections import Counter
from django.db.models import Count
cntr = Counter()
for relation in Tag._meta.fields_map:
cntr.update(
{
tg: tg.nr
for tg in Tag.objects.annotate(nr=Count(relation)).order_by('nr')
}
)