Django累加投资余额时报'QuerySet'对象无balance属性错误如何解决
报错根因
Investment.objects.all() 返回的是存储所有Investment表记录的QuerySet集合对象,不是单条Investment模型实例,balance是模型实例上的字段,集合本身不存在这个属性,直接访问就会抛出'QuerySet' object has no attribute 'balance'异常。
另外现有代码还有两个逻辑缺陷:
- 没有关联充值操作对应的用户,根本无法区分余额属于哪个用户
- 就算拿到了实例,修改字段后没有调用
save()方法,余额更新不会持久化到数据库
修复方案
1. 完善Investment模型
给模型加和用户的一对一关联,确保每个用户对应独立的投资账户,给balance加默认值避免新账户初始值为空报错:
from django.db import models from django.contrib.auth import get_user_model User = get_user_model() class Investment(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="investment_account") balance = models.IntegerField(default=0)
修改完模型记得执行python manage.py makemigrations和python manage.py migrate同步数据库结构。
2. 修正视图逻辑
替换原来的全表查询,定位到当前登录用户的账户实例,完成余额累加后保存数据:
def create_investment_view(request): if request.method == "POST": form = InvestmentForm(request.POST) if form.is_valid(): amount = form.cleaned_data["amount"] # 获取当前用户的投资账户,不存在则自动创建初始记录 user_investment, _ = Investment.objects.get_or_create(user=request.user) # 累加充值金额 user_investment.balance += amount # 持久化修改到数据库 user_investment.save() # 可根据业务需求添加成功提示、跳转逻辑 else: form = InvestmentForm() context = {"form": form} return render(request, "create-investment.html", context)
3. 高并发场景优化
如果充值请求并发量高,上面先查询再修改保存的逻辑会出现竞态条件(多个请求同时读到旧余额,覆盖彼此的更新),推荐用数据库原子更新替代:
from django.db.models import F def create_investment_view(request): if request.method == "POST": form = InvestmentForm(request.POST) if form.is_valid(): amount = form.cleaned_data["amount"] user_inv = Investment.objects.filter(user=request.user) if user_inv.exists(): # 直接在数据库层执行余额累加,无需先查询实例 user_inv.update(balance=F("balance") + amount) else: # 不存在记录则先创建 Investment.objects.create(user=request.user, balance=amount) else: form = InvestmentForm() context = {"form": form} return render(request, "create-investment.html", context)
F()表达式的更新逻辑直接在数据库端执行,全程不会把余额值加载到Python内存,从根本上避免并发更新覆盖的问题。
内容的提问来源于stack exchange,提问作者Thaddeaus Iorbee
相关产品推荐
相关产品推荐

