Django 过滤器 table 并按计数排序

Django filter table and sort by count

我正在尝试从一个 table 中获取行,其条目在另一个 table 中具有最多的匹配项,引用了一个 manytomany 字段。

有效的SQL是:

SELECT *, COUNT(*) FROM events_event_genres
LEFT JOIN events_event
ON event_id = events_event.id
WHERE genre_id IN (6,9,31)
AND start_date > '2016-08-06'
GROUP BY event_id
ORDER BY COUNT(*) DESC
LIMIT 10

事件模型有:

class Event(models.Model):
    title = models.CharField(max_length=250) 
    start_date = models.DateTimeField()
    genres = models.ManyToManyField("genres.Genre", blank=True, null=True, related_name="events")

在我看来我已经尝试过:

results = Event.objects.filter(
    Q(genres__id__in=genres),
    Q(start_date__gte=datetime.date.today()) \
    .annotate(event=Count('id')) \
    .order_by('event')

我得到的结果几乎与这个 SQL 查询相同:

SELECT * FROM events_event
LEFT JOIN events_event_genres
ON events_event.id = event_id
WHERE genre_id IN (6,9,31)
AND start_date > '2016-08-06'
LIMIT 10

很明显计数不起作用。

django 的方法是什么?

离你不远了。此查询应该有效:

Event.objects.filter(genres__in=genres, start_date__gte=datetime.date.today())\
.distinct().annotate(num_genres=Count('genres')).order_by('-num_genres')

生成的查询集中的每个 Event 对象都会有一个 num_genres 属性,其中包含匹配的流派数量。它们将按匹配流派的数量排序。

结果 SQL 是:

SELECT DISTINCT "events_event"."id", "events_event"."name", 
COUNT("events_event_genres"."genre_id") AS "n" 
FROM "events_event" INNER JOIN "events_event_genres" 
ON ( "events_event"."id" = "events_event_genres"."event_id" ) 
WHERE "events_event_genres"."genre_id" IN (g1) 
GROUP BY "events_event"."id", "events_event"."name" 
ORDER BY "n" DESC