You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中exclude(id=id)的id获取及关联产品平均评分显示问题

问题解决步骤

1. 搞懂.exclude(id=id)的逻辑

这里两个id的含义不同:

  • 第一个id是Product模型的主键字段(Django默认生成的主键)
  • 第二个id是当前详情页对应的产品ID,也就是你从URL路由里捕获的参数(比如视图函数def product_detail(request, id):里的id)
    这条语句的作用是:筛选出和当前产品同分类的所有产品,但排除当前产品本身,避免关联产品列表里出现自己。

2. 修复当前产品的评分展示问题

先检查views.py的产品详情视图,确保已计算当前产品的平均评分并传入模板:

from django.db.models import Avg

def product_detail(request, id):
    product = Product.objects.get(id=id)
    # 计算当前产品平均评分,处理无评论的情况
    avg_reviews = ProductReview.objects.filter(product=product).aggregate(avg_rating=Avg('review_rating'))
    # 无评论时给默认值0,避免模板显示None
    avg_reviews['avg_rating'] = avg_reviews['avg_rating'] or 0
    # 关联产品查询保留原有逻辑
    related_products = Product.objects.filter(category=product.category).exclude(id=id)
    
    # 把计算好的评分传入模板上下文
    context = {
        'product': product,
        'avg_reviews': avg_reviews,
        'related_products': related_products,
    }
    return render(request, 'product-detail.html', context)

然后修改模板product-detail.html,优化评分显示格式:

<span class="avg-rating">{{ avg_reviews.avg_rating|floatformat:1 }}</span>/5

如果之前视图没把avg_reviews传入上下文,模板自然拿不到值,这是最常见的问题。

3. 实现关联产品的平均评分展示

不要循环每个关联产品单独计算评分(会产生N+1查询,效率极低),直接用annotate在数据库层面批量计算:
修改views.py里的关联产品查询:

from django.db.models import Avg, Case, When, Value, FloatField

related_products = Product.objects.filter(category=product.category).exclude(id=id).annotate(
    avg_rating=Case(
        # 有评论的产品计算平均分,无评论返回0
        When(productreview__isnull=False, then=Avg('productreview__review_rating')),
        default=Value(0.0),
        output_field=FloatField()
    )
)

之后在模板里遍历关联产品时,直接调用自带的avg_rating属性:

{% for item in related_products %}
    <div class="related-product-item">
        <h4>{{ item.name }}</h4>
        <span class="avg-rating">{{ item.avg_rating|floatformat:1 }}</span>/5
    </div>
{% endfor %}

补充:检查模型关联正确性

确保ProductReview的外键关联配置正确:

# models.py
class ProductReview(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='productreview')
    review_rating = models.IntegerField(choices=[(1,1),(2,2),(3,3),(4,4),(5,5)])
    # 其他字段...

如果没设置related_name,默认是productreview_set,那annotate里要改成Avg('productreview_set__review_rating')。


内容的提问来源于stack exchange,提问作者Artem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:52:45