Django重写模型save方法后basic_interest返回0问题排查
问题原因
你遇到这个问题的核心原因有两个:
form.save(commit=False)的执行逻辑是仅生成模型实例、不写入数据库,不会触发你在模型类中重写的save()方法。你写在模型save里的利息计算逻辑在你执行print语句时根本没有运行,此时basic_interest没有被赋值,自然会打印出0。- 字段类型和计算结果不匹配:你将
basic_interest定义为IntegerField(整数字段),但计算公式self.basic_deposit_amount * 365 * 0.02/2返回的是浮点数,就算save方法正常执行,浮点数存入整数字段时会被强制截断,金融场景下用浮点数计算还容易出现精度误差。
另外你代码里还有两个隐藏问题:
- 表单校验失败时你用了
messages.success做提示,语义不对,应该用错误级别的消息 - 视图里操作了
basic_investment_return字段,但你贴出的模型代码里没有定义这个字段,运行时会抛出属性不存在的错误
修复方案
- 把利息计算逻辑从save方法里抽成独立的实例方法,既可以在save时自动执行保证存库数据正确,也可以在需要拿计算值的时候手动调用。
- 把
basic_interest换成适合金融计算的DecimalField,避免精度丢失和类型不匹配问题。
修正后的模型代码:
# Models.py from django.db import models class Investment(models.Model): basic_deposit_amount = models.IntegerField(null=True) # 用DecimalField存金额类数据,根据业务调整最大位数和小数位 basic_interest = models.DecimalField(max_digits=12, decimal_places=2, null=True) # 补上视图里用到的缺失字段,根据业务调整字段类型 basic_investment_return = models.DecimalField(max_digits=12, decimal_places=2, default=0) is_active = models.BooleanField(default=False) def calc_basic_interest(self): if self.basic_deposit_amount: # 保留你原来的计算逻辑:年化2%,按半年计息 self.basic_interest = self.basic_deposit_amount * 365 * 0.02 / 2 return self.basic_interest def save(self, *args, **kwargs): # 存库前自动计算利息 self.calc_basic_interest() super().save(*args, **kwargs)
修正后的视图代码:
# views.py from django.contrib import messages from django.shortcuts import render from .forms import BasicInvestmentForm def create_investment_view(request): if request.method == 'POST': basic_investment_form = BasicInvestmentForm(request.POST) if basic_investment_form.is_valid(): investment = basic_investment_form.save(commit=False) # 手动调用计算方法,此时就能拿到正确的利息值 investment.calc_basic_interest() investment.basic_investment_return += investment.basic_deposit_amount print(investment.basic_interest) print(investment.basic_investment_return) print(investment.basic_deposit_amount) investment.is_active = True investment.save() messages.success(request, f'your basic investment of {investment.basic_deposit_amount} is successfull ') else: # 校验失败用error级别提示 messages.error(request, 'your investment is not successfull! Try again.') else: basic_investment_form = BasicInvestmentForm() context = {'basic_investment_form': basic_investment_form} return render(request, 'create-basic-investment.html', context)
改完之后,你在print语句位置就能拿到正确计算后的basic_interest值,最终存库的数据也会经过计算逻辑校验,不会出现值为0的问题。
内容的提问来源于stack exchange,提问作者Thaddeaus Iorbee
相关产品推荐
相关产品推荐

