我有一个数据库模型,如下所示。将数据视为2本不同的书籍,每本书都有3个评级。
class Book(models.Model):
name = models.CharField(max_length=50)
class Review(models.Model):
book = models.ForeignKey(Book)
review = models.CharField(max_length=1000)
rating = models.IntegerField()
问题:是否可以使用单个查询为每本书对列表中的所有评分进行分组。我希望在数据库级别执行此操作,而无需在代码中迭代Queryset。输出应该类似于:
{
'book__name':'book1',
'rating' : [3, 4, 4],
'average' : 3.66,
'book__name':'book2',
'rating : [2, 1, 1] ,
'average' : 1.33
}
我已经尝试过此查询,但按图书名称分组的评分也不是,平均值也不正确:
Review.objects.annotate(average=Avg('rating')).values('book__name','rating','average')
修改:添加说明我正在寻找在数据库级别对元素进行分组的方法。
答案 0 :(得分:8)
你可以这样做。希望这会有所帮助。
Review.objects.values('book__name').annonate(average=Avg('rating'))
<强>更新强>
如果您想要列表中特定图书的所有评级,那么您可以这样做。
from collections import defaultdict
ratings = defaultdict(list)
for result in Review.objects.values('book__name', 'rating').order_by('book__name', 'rating'):
ratings[result['book__name']].append(result['rating'])
你会得到这样的结构:
[{ book__name: [rating1, rating2, ] }, ]
<强>更新强>
q = Review.objects.values('book__name').annonate(average=Avg('rating')).filter().prefetech_related('rating')
q[0].ratings.all() # gives all the ratings of a particular book name
q[0].average # gives average of all the ratings of a particular book name
希望这有效(我不确定,抱歉),但您需要添加related_ name
属性
class Review(models.Model):
book = models.ForeignKey(Book, related_name='rating')
<强>更新强>
很抱歉,但是你需要在SQL中称为GROUP_CONCAT的东西,但目前在Django ORM中不支持它。
您可以使用Raw SQL或itertools
from django.db import connection
sql = """
SELECT name, avg(rating) AS average, GROUP_CONCAT(rating) AS rating
FROM book JOIN review on book.id = review.book_id
GROUP BY name
"""
cursor = connection.cursor()
cursor.execute(sql)
data = cursor.fetchall()