简体   繁体   English

如何在 Django 的多对多关系中分组?

[英]How to group by in ManyToMany relationships in Django?

I am creating a web application with Django and I have some problems using its ORM to make queries.我正在使用 Django 创建一个 web 应用程序,我在使用它的 ORM 进行查询时遇到了一些问题。 I have these models:我有这些模型:

class Country(models.Model):
name = models.CharField(max_length=25)

class Song(models.Model):
title = models.CharField(max_length = 25)
country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name="songs")
ratings = models.ManyToManyField(Country, through='Rating')

class Rating(models.Model):
rating = models.PositiveSmallIntegerField()
country_id = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
song_id = models.ForeignKey(Song, on_delete=models.SET_NULL, null=True)

A Country rates many Songs (with ratings 1-10), and a Song can be rated by many Countries, so there's a ManyToMany relationship between these models through the Rating table.一个国家对许多歌曲进行评级(评级为 1-10),而一首歌曲可以被许多国家评级,因此这些模型之间通过评级表存在多对多关系。 I am making a query to get the number of 10 points a Song has received, but I don't know how.我正在查询一首歌曲获得的 10 分,但我不知道如何。 To do that, I tried this query:为此,我尝试了以下查询:

result = Rating.objects.filter(rating=10).values('song_id').annotate(ten_points = Count('rating'))

I read Django documentation and I understood that values() method is like group by clause in SQL, but it doesn't work because this query returns a queryset of dictionaries like this:我阅读了 Django 文档,我了解到 values() 方法类似于 SQL 中的 group by 子句,但它不起作用,因为此查询返回这样的字典查询集:

<QuerySet [{'song_id': 1, 'ten_points': 1}, {'song_id': 2, 'ten_points': 1}, {'song_id': 2, 'ten_points': 1}, {'song_id': 3, 'ten_points': 1}, {'song_id': 3, 'ten_points': 1} 

Why am I getting different dictionaries with the same key and value 1, instead of a dictionary with the key and the value the total number of ten points?为什么我得到具有相同键和值 1 的不同字典,而不是键和值是十点总数的字典?

You need to use .order_by(…) to force grouping, so:您需要使用.order_by(…)强制分组,所以:

result = Rating.objects.filter(rating=10).values(
    'song_id'
).annotate(ten_points=Count('rating')).order_by('song_id')

But in this specific case, it might make more sense to annotate the Song s:但在这种特定情况下,注释Song s 可能更有意义:

Song.objects.filter(
    rating__rating=10
).annotate(
    ten_points=Count('rating')
)

This will only include Song s that have at least one Rating record with rating=10 .这将仅包括具有至少一个Rating rating=10Rating记录的Song If you want to annotate all Song s, you can use:如果要对所有Song进行注解,可以使用:

from django.db.models import Q

Song.objects.annotate(
    ten_points=Count('rating', filter=Q(rating__rating=10))
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM