Django中更新用户余额时触发TypeError: save()缺少必填参数'self'的问题求助
解决Django更新用户余额时的TypeError: save() missing required positional argument 'self'
嘿,这个问题我之前也碰到过!你犯了一个Django新手很容易踩的坑:直接在模型类balance_data上操作属性并调用save(),但save()是模型实例的方法,必须绑定到具体的用户余额对象上才能用,不能直接调用类的save()。
为啥会报错?
看你Views里的这段代码:
def cash_in(request, amount): new_amount = request.user.balance_data.total_amount + amount balance_data.total_amount = new_amount # 这里改的是整个模型类的属性,不是当前用户的余额记录! balance_data.save() # 调用类的save方法,当然缺self参数啦——self得是具体的实例呀 return HttpResponse(request.user.balance_data.total_amount)
balance_data是你的模型类,不是当前登录用户对应的那条余额数据。你现在的操作相当于试图给整个余额表改个全局的total_amount,这完全不是你要的效果,而且类的save方法根本没有实例上下文,所以才会报缺少self的错误。
直接修复的代码
你要操作的是request.user.balance_data这个已经和当前用户关联的实例,直接改它、存它就行:
def cash_in(request, amount): # 拿到当前用户的专属余额实例 user_balance = request.user.balance_data # 直接累加金额 user_balance.total_amount += amount # 调用实例的save方法,这时候self就是user_balance本身啦 user_balance.save() # 返回更新后的余额 return HttpResponse(user_balance.total_amount)
进阶优化:解决并发更新的坑
如果你的网站有多人同时操作余额的场景(比如用户同时发起两次充值),上面的写法可能会出问题——两个请求同时读取旧余额,各自加值后保存,最后余额只加了一次。这时候用Django的F()表达式就能解决,它会直接在数据库层面做原子更新,不会读旧值:
先在views顶部导入F:
from django.db.models import F
然后修改视图:
def cash_in(request, amount): # 直接让数据库执行余额累加,全程不读取旧值,避免并发冲突 request.user.balance_data.update(total_amount=F('total_amount') + amount) # 因为F操作是在数据库层面做的,内存里的实例还没更新,所以要刷新一下 request.user.balance_data.refresh_from_db() return HttpResponse(request.user.balance_data.total_amount)
额外提醒
- 要确保每个用户都有对应的
balance_data实例,不然request.user.balance_data会报错。可以用Django的post_save信号,在用户创建时自动生成余额记录。 - 你的
FloatField加了max_length=15是没用的,数值类型不支持这个参数,建议删掉。如果要保证金额精度,最好用DecimalField(max_digits=15, decimal_places=2),避免浮点数的精度丢失问题。
内容的提问来源于stack exchange,提问作者Mehedi Hasan
相关产品推荐
相关产品推荐

