Django视图中处理单个Photo实例点赞逻辑时循环报错的解决方法
解决Django视图中点赞逻辑的报错与优化方案
嘿,我来帮你搞定这个问题!先说说你遇到的报错原因,再给你两种可行的解决方案~
一、报错根源:误用内置函数id
你代码里的pic_likes = all_likes.filter(photo_id=id)这一行有问题:这里的id是Python的内置函数,不是当前循环中photo实例的ID,所以Django尝试把这个内置函数转成整数时就抛出了int() argument must be a string, a bytes-like object or a number, not 'builtin_function_or_method'的错误。
修正后的基础写法(基于你现有的Like模型)
先把id改成photo.id,同时优化查询逻辑(不要先查所有Like再过滤,直接针对当前photo查询,而且用exists()代替len()更高效,因为exists()会在数据库层面做判断,不用加载所有数据):
def your_view(request): photos = Photo.objects.all() for photo in photos: # 直接查询当前photo的所有点赞记录 pic_likes = Like.objects.filter(photo=photo) # 点赞数直接用count(),比len()更高效 photo.like_count = pic_likes.count() # 判断当前用户是否点赞过,用exists()替代len(liker)!=0 photo.liked = pic_likes.filter(liker=request.user).exists() return render(request, 'your_template.html', {'photos': photos})
然后在模板里就可以直接用这些新增的属性了:
{% for photo in photos %} <div> <p>作者:{{ photo.author }}</p> <p>点赞数:{{ photo.like_count }}</p> {% if photo.liked %} <button>已点赞</button> {% else %} <button>点赞</button> {% endif %} </div> {% endfor %}
二、更优方案:利用Photo模型自带的ManyToMany字段
仔细看你的Photo模型,已经定义了likes = models.ManyToManyField(User, related_name='likes'),这个字段本身就可以实现“用户-照片”的点赞关联,完全不需要额外的Like模型(除非你需要记录点赞时间、点赞状态的变更历史这类额外信息)。
用这个字段的话,逻辑会简洁很多:
def your_view(request): photos = Photo.objects.all() for photo in photos: # 直接获取点赞数 photo.like_count = photo.likes.count() # 判断当前用户是否点赞过 photo.liked = photo.likes.filter(id=request.user.id).exists() return render(request, 'your_template.html', {'photos': photos})
甚至可以用prefetch_related提前预加载点赞数据,避免循环里的N+1查询问题,大幅提升性能:
from django.db.models import Prefetch def your_view(request): # 预加载每个photo的点赞用户,同时过滤当前用户的点赞记录 photos = Photo.objects.all().prefetch_related( Prefetch('likes', queryset=User.objects.filter(id=request.user.id), to_attr='user_liked') ) for photo in photos: photo.like_count = photo.likes.count() photo.liked = len(photo.user_liked) > 0 return render(request, 'your_template.html', {'photos': photos})
模板里的用法和之前完全一样,这样既简化了代码,又提升了查询效率~
内容的提问来源于stack exchange,提问作者FANCY_HOOMAN
相关产品推荐
相关产品推荐

