Django首页模板获取商品点赞数及多商品点赞问题求助
Django商品点赞功能异常修复方案
问题描述
我尝试在首页模板中显示每个商品的点赞数,页面包含多个商品,但当前代码运行时Django抛出各类异常,无法正常实现功能。
现有代码
views.py
@login_required def home(request): products = Product.objects.all() like_counts = {product.id: Like.objects.filter(product=product).count() for product in products} liked_products = Like.objects.filter(user=request.user, product__in=products).values_list('product', flat=True) context = { "products": products, "liked_products": liked_products, "like_counts": like_counts, "categories": Category.objects.all(), } return render(request, 'shop/index.html', context) @login_required def likeProduct(request, product_id): product = get_object_or_404(Product, id=product_id) # Check if the user has already liked the product if not Like.objects.filter(user=request.user, product=product).exists(): # Create a new Like object Like.objects.create(user=request.user, product=product) print('product liked') likes = Like.objects.all().count return JsonResponse({"status": "success","likes":f'{likes}'}) else: liked = Like.objects.get(user=request.user) liked.delete() print('product like removed') likes = Like.objects.all().count return JsonResponse({"status": "success","likes":f'{likes}'}) def views_count(request,product_id): item = Product.objects.get(id=product_id) item.views_count += 1 item.save() return redirect('home')
index.html
{% csrf_token %} <div class="d-flex justify-content-between"> <button onclick="likeProduct({{ product.id }})" class="btn shadow-none bg-transparent rounded-pill"> <i class="{% if product.id in liked_products %}fas{% else %}far{% endif %} fa-heart"></i> {{ like_counts|default:"0"|get:product.id }} </button> <button class="btn shadow-none bg-transparent rounded-pill"><i class="fas fa-star"></i></button> <button class="btn btn-outline-primary"><i class="fas fa-comment"></i></button> </div>
错误点分析
- 取消点赞查询错误:
Like.objects.get(user=request.user)仅按用户查询会返回多条记录,引发MultipleObjectsReturned异常,需同时指定product过滤条件。 - 点赞数统计错误:
Like.objects.all().count是引用方法而非调用,需添加();且应统计当前商品的点赞数,而非所有商品的总点赞数。 - 模板取值错误:Django模板无
get过滤器,直接用like_counts[product.id]会在键不存在时报错,需用安全的取值方式。 - 视图异常未处理:
views_count中用Product.objects.get()会引发DoesNotExist异常,需改用get_object_or_404。 - 查询效率低下:循环每个product统计点赞数会产生N+1次数据库查询,应改用
annotate批量统计。
修复后的代码
views.py
from django.db.models import Count @login_required def home(request): # 用annotate批量统计每个商品的点赞数,提升查询效率 products = Product.objects.annotate(like_count=Count('like')) liked_products = Like.objects.filter(user=request.user, product__in=products).values_list('product_id', flat=True) context = { "products": products, "liked_products": liked_products, "categories": Category.objects.all(), } return render(request, 'shop/index.html', context) @login_required def likeProduct(request, product_id): product = get_object_or_404(Product, id=product_id) like_obj, created = Like.objects.get_or_create(user=request.user, product=product) if created: # 新增点赞逻辑 print('product liked') else: # 取消点赞逻辑 like_obj.delete() print('product like removed') # 获取当前商品最新点赞数 current_likes = Like.objects.filter(product=product).count() return JsonResponse({"status": "success", "likes": current_likes}) def views_count(request, product_id): item = get_object_or_404(Product, id=product_id) item.views_count += 1 item.save() return redirect('home')
index.html
{% csrf_token %} <div class="d-flex justify-content-between"> <button onclick="likeProduct({{ product.id }})" class="btn shadow-none bg-transparent rounded-pill"> <i class="{% if product.id in liked_products %}fas{% else %}far{% endif %} fa-heart"></i> {{ product.like_count|default:0 }} </button> <button class="btn shadow-none bg-transparent rounded-pill"><i class="fas fa-star"></i></button> <button class="btn btn-outline-primary"><i class="fas fa-comment"></i></button> </div>
额外说明
- 修复后的代码使用
annotate将点赞数直接注入Product对象,避免额外的字典存储和重复查询。 - 用
get_or_create简化点赞/取消点赞的逻辑,减少冗余代码。 - 模板直接调用
product.like_count,更直观且避免过滤器错误。
内容的提问来源于stack exchange,提问作者Leroy Mapunzwana
相关产品推荐
相关产品推荐

