Django2.0从SQLite迁移至PostgreSQL9.6.3后遇两类数据库异常求助
解决Django从SQLite迁移到PostgreSQL的两个数据类型问题
我来帮你解决这两个从SQLite迁移到PostgreSQL时遇到的Django问题,都是挺常见的类型适配坑:
问题1:FloatField聚合时触发DataError: invalid input syntax for integer: "none"
问题原因
你在Cast(Sum(...), DecimalField(decimal_places=2))里只指定了decimal_places,没有传max_digits参数。Django生成SQL时,会把缺失的max_digits渲染成None,导致PostgreSQL收到非法的numeric(None,2)类型定义,直接报错。
解决方法
给Cast里的DecimalField同时补全max_digits和decimal_places参数,确保PostgreSQL能识别合法的numeric类型。结合你原字段的max_digits=7,加上两位小数,把max_digits设为9足够覆盖范围:
object_list = WechatPay.objects.values('user', 'trade_date', 'user_group').filter(...) .annotate( card_sale=Cast(Sum('card_sale'), DecimalField(max_digits=9, decimal_places=2)), total_fee=Cast(Sum('total_fee'), DecimalField(max_digits=9, decimal_places=2)), card_recharge=Cast(Sum('card_recharge'), DecimalField(max_digits=9, decimal_places=2)) ).order_by('-trade_date')
PostgreSQL的numeric类型要求同时指定精度(总位数)和刻度(小数位数),补全参数后生成的SQL就会变成合法的numeric(9,2),问题解决。
问题2:DecimalField字段保存后值变为0
问题原因
你修改后的DecimalField设置了decimal_places=0,这意味着该字段只存储整数部分。哪怕你传入了带小数的Decimal值,Django会自动截断小数部分,所以0.209999...被截断后就变成了0。另外,用float转Decimal的方式也容易引入精度误差,尽量避免。
解决方法
- 修正模型字段定义:把
decimal_places改成你需要的小数位数(比如金额常用的2位),同时调整max_digits适配总位数:
class WechatPay(models.Model): # ... 其他字段保持不变 total_fee = models.DecimalField('订单金额', default=0, decimal_places=2, max_digits=9) card_sale = models.DecimalField('售卡款', default=0, decimal_places=2, max_digits=9) card_recharge = models.DecimalField('充值款', default=0, decimal_places=2, max_digits=9)
- 优化金额转换逻辑:避免用
float中转,直接用整数和Decimal计算,保证精度:
# 从接口获取的total_fee是整数(单位分),直接转Decimal后除以100 total_fee_int = int(result[0].get('total_fee')) trade_log.total_fee = Decimal(total_fee_int) / Decimal(100) trade_log.save()
- 更新数据库结构:修改模型后必须执行迁移命令,确保PostgreSQL的表字段同步更新:
python manage.py makemigrations python manage.py migrate
这样修改后,带小数的金额就能被正确存储到数据库中了。
内容的提问来源于stack exchange,提问作者Xie.YJ
相关产品推荐
相关产品推荐

