Django模型IntegerField值加减后页面显示DeferredAttribute对象问题
问题原因
页面渲染出<django.db.models.query_utils.DeferredAttribute object at 0x...>的直接原因是视图中这行错误代码:
following_num = User.following_num
User.following_num是模型类层面的字段定义对象,不是某个用户实例的实际字段值,模板渲染类属性时就会输出这类对象信息。
原有代码另外存在三个逻辑问题:
- 关注/取关触发的数值加减仅生成了局部变量,没有将更新结果写入数据库,页面刷新后数值会还原
- 统计对象错位:代码取当前登录访问者的关注数,当作被访问主页用户的粉丝/关注数返回,统计逻辑完全错误
- 先取值再加减的实现存在并发竞态问题,多用户同时操作时会出现计数不准的情况
修复方案
方案一(推荐):直接用多对多关系的count()统计,无需维护冗余字段
你的following多对多字段已经设置了related_name="followers",关联表会自动维护关注关系,直接调用count()就能拿到准确数值,完全不需要额外的following_num字段,从根源避免计数不一致问题。
修正后的视图函数代码:
from django.shortcuts import redirect def username(request, user): # 获取被访问的主页用户 profile_user = get_object_or_404(User, username=user) posts = Post.objects.filter(user=profile_user).order_by('-date_and_time') current_user = request.user # 访问自己的主页时不显示关注按钮 followButton = profile_user != current_user if request.method == "POST": if "follow" in request.POST: current_user.following.add(profile_user) elif "unfollow" in request.POST: current_user.following.remove(profile_user) # 操作后重定向,避免表单重复提交 return redirect("username", user=profile_user.username) # 直接通过多对多关系统计数量,永远和实际关注关系一致 followers_count = profile_user.followers.count() following_count = profile_user.following.count() return render(request, "network/username.html",{ "user": profile_user, "posts": posts, "followButton": followButton, "followers": followers_count, "following": following_count })
方案二:保留IntegerField计数字段的修复方式
如果一定要保留following_num字段做计数,需要注意更新时用F表达式做原子更新,更新后存库,且取值必须取实例的字段值,禁止直接引用类属性:
- 首先补全模型里缺失的粉丝数字段(原有模型只定义了关注数):
class User(AbstractUser): following = models.ManyToManyField("self", related_name="followers", symmetrical=False) following_num = models.IntegerField(default=0) # 本人关注的人数 followers_num = models.IntegerField(default=0) # 本人的粉丝数
- 修正视图逻辑:
from django.db.models import F from django.shortcuts import redirect def username(request, user): profile_user = get_object_or_404(User, username=user) posts = Post.objects.filter(user=profile_user).order_by('-date_and_time') current_user = request.user followButton = profile_user != current_user if request.method == "POST": if "follow" in request.POST: current_user.following.add(profile_user) # 原子更新计数,避免竞态 current_user.following_num = F('following_num') + 1 profile_user.followers_num = F('followers_num') + 1 elif "unfollow" in request.POST: current_user.following.remove(profile_user) current_user.following_num = F('following_num') - 1 profile_user.followers_num = F('followers_num') - 1 # 保存更新 current_user.save() profile_user.save() # 重定向避免重复提交 return redirect("username", user=profile_user.username) # 必须传实例的字段值,不能传User.following_num这类类属性 return render(request, "network/username.html",{ "user": profile_user, "posts": posts, "followButton": followButton, "followers": profile_user.followers_num, "following": profile_user.following_num })
修复验证
修改后模板不需要做任何调整,页面会正常渲染整数类型的关注/粉丝数,不会再出现DeferredAttribute的对象输出。关注/取关按钮点击后数值会正常更新,刷新页面也不会丢失。
内容的提问来源于stack exchange,提问作者econo
相关产品推荐
相关产品推荐

