如何在Django中创建带ManyToMany关系的过滤注解?
我有一个模型,里面有文章、事件和人物:
class Person(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=30)
class Event(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=200)
class Article(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=200)
publishDate = models.DateTimeField(blank=True, null=True)
event = models.ForeignKey(Event, blank=False, null=False)
persons = models.ManyToManyField(Person)
一篇文章属于一个事件,而一个事件可以包含很多篇文章。人物出现在很多篇文章中,而文章也包含很多人物。我的想法是查看在特定时间段内,哪些事件被写得最多。我通过一次查询就实现了这一点:
topEvents = Article.objects.filter(publishDate__gt=dateStart)
.filter(publishDate__lt=dateEnd)
.values('event').annotate(count=Count('id'))
.order_by('-count')[:topN]
我发现这样做比在服务器端计算前N名要快很多。
现在,我的问题是,如何处理我和人物之间的多对多关系?另外,这样做是否是最好的方式?
2 个回答
0
你试过这个吗:
topUsers = Article.objects.filter(publishDate__gt=dateStart)
.filter(publishDate__lt=dateEnd)
.values('persons').annotate(count=Count('id'))
.order_by('-count')[:topN]
6
为了让你的例子更简单明了:
class Event(models.Model):
title = models.CharField(max_length=200)
class Person(models.Model):
name = models.CharField(max_length=30)
class Article(models.Model):
title = models.CharField(max_length=200)
publishDate = models.DateTimeField(blank=True, null=True)
event = models.ForeignKey(Event, related_name='articles')
persons = models.ManyToManyField(Person, related_name='articles')
注意,这里没有 id
字段,因为 Django 会自动为我们生成这些字段。此外,在 Article
类中,event
和 persons
的 related_name
都设置为 'articles',这意味着我们可以通过 event.articles
和 person.articles
来简单地引用文章。
现在,如果你想找出被提到最多的事件和人物,可以直接在它们的模型管理器上进行查询:
Event.objects.filter(articles__publishDate__gt=dateStart)\
.filter(articles__publishDate__lt=dateEnd)\
.annotate(count=Count('articles')).order_by('-count')
Person.objects.filter(articles__publishDate__gt=dateStart)\
.filter(articles__publishDate__lt=dateEnd)\
.annotate(count=Count('articles')).order_by('-count')