我有一个简单的产品和评分类,如下所示:
class Product(models.Model):
name = ...
price = ...
class Rating(models.Model):
product = models.ForeignKey("Product", ...)
score = models.PositiveSmallIntegerField(...)
现在,我想获取所有产品的列表以及每种产品的平均评分。简单地获取所有产品很容易:
product_list = Product.objects.all()
如果我有一个产品,并且想获得该产品的平均评分:
product = get_object_or_404(Product, pk=product_id)
ratings = Rating.objects.filter(product=product)
product_avg_rating = ratings.aggregate((Avg("score")))
但是,假设我要列出所有产品及其平均评分。听起来资源/计算量很大。那么解决此问题的最佳方法是什么?我是否应该为Product类创建一个仅返回平均值的类方法,然后再在模板中调用它:
{{ product.get_average_rating }}
或者有更好的方法吗?我不太确定该怎么做,需要一些指导。
非常感谢您!
编辑:我认为我的解释不够清楚,因此这是一个实际示例。假设我有一个查询集,该查询集由slug(这只是一个搜索字词)过滤:
products = Product.objects.filter(tags__name__in=[slug])
现在如何将平均评分添加到每个产品中,以便可以在模板中执行此操作:
{% for product in products %}
{{ product.avg_rating_score }}
{% endfor %}
答案 0 :(得分:1)
您可以在第一个查询中注释Product
,这样只需一个查询即可获得平均值,例如:
product = get_object_or_404(
Product.object.annotate(avg_score=Avg('rating__score')),
pk=product_id
)
这将导致单个Product
包含一个额外的属性(仅针对 this 特定的QuerySet
!),因此,我们可以在模板中使用以下属性进行渲染:
{{ product.avg_score }}
它执行的查询是:
SELECT product.*, AVG(rating.score) AS avg_score
FROM product
LEFT OUTER JOIN rating ON product.id = rating.product_id
WHERE product.id = product_id