You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中DecimalField查询触发decimal.InvalidOperation异常求助

问题排查:Django DecimalField 触发 decimal.InvalidOperation 异常

问题场景

使用DecimalField定义模型字段时,执行数据库查询会抛出decimal.InvalidOperation异常,将字段改为IntegerField后恢复正常。

异常版本模型代码

class Item(models.Model):
    ....
    price = models.DecimalField(max_digits=5, decimal_places=2, help_text="Цена товара", verbose_name="Цена")
    # price = models.IntegerField(help_text="Цена товара", verbose_name="Цена")

查询代码

class ProductBuyView(APIView):
    def get(self, request, item_uuid: str, format=None):
        product = Item.objects.all().filter(uuid__exact=uuid.UUID(item_uuid))[0]
        ...

异常栈信息

File "/home/lev/python_projects/taste_case_stripe/stripe_app/views.py", line 14, in get
    product = Item.objects.all().filter(uuid__exact=uuid.UUID(item_uuid))[0]
  File "/home/lev/python_projects/taste_case_stripe/venv/lib/python3.10/site-packages/django/db/models/query.py", line 445, in __getitem__
    qs._fetch_all()
  File "/home/lev/python_projects/taste_case_stripe/venv/lib/python3.10/site-packages/django/db/models/query.py", line 1866, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/lev/python_projects/taste_case_stripe/venv/lib/python3.10/site-packages/django/db/models/query.py", line 117, in __iter__
    for row in compiler.results_iter(results):
  File "/home/lev/python_projects/taste_case_stripe/venv/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1333, in apply_converters
    value = converter(value, expression, connection)
  File "/home/lev/python_projects/taste_case_stripe/venv/lib/python3.10/site-packages/django/db/backends/sqlite3/operations.py", line 344, in converter
    return create_decimal(value).quantize(
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

正常版本模型代码

class Item(models.Model):
    ....
    price = models.IntegerField(help_text="Цена товара", verbose_name="Цена")

原因分析与解决方案

核心原因

SQLite没有原生DECIMAL类型,Django会将DecimalField映射为TEXT或REAL类型存储。当数据库中存储的数值不符合DecimalField定义的约束,或格式无法被Decimal转换器解析时,就会触发InvalidOperation异常。具体可能的情况包括:

  • 存储了非数值内容(如空字符串、字母)
  • 小数位数超过decimal_places=2(如12.345)
  • 总位数超过max_digits=5(如1234.56,总位数为6)
  • 数据迁移时未正确转换原IntegerField存储的值(虽然整数转Decimal通常没问题,但特殊格式可能引发异常)

排查与解决步骤

  1. 检查数据库原始数据
    直接查询SQLite数据库,查看目标UUID对应的price值:

    SELECT price FROM stripe_app_item WHERE uuid = '目标UUID值';
    

    确认是否存在格式错误、超出精度的数据。

  2. 修复异常数据
    对不符合约束的数据进行修正:

    • 超出小数位的数值四舍五入到2位小数
    • 删除或替换非数值内容
    • 截断或调整超出总位数限制的数值
  3. 验证数据转换逻辑
    临时添加调试代码,查看数据库返回的原始值:

    raw_price = Item.objects.filter(uuid__exact=uuid.UUID(item_uuid)).values('price').first()
    print(raw_price) # 打印原始price值,确认格式是否正确
    
  4. 重新执行迁移(若需)
    如果是字段类型变更时未正确处理数据,先备份数据库,然后重新生成并执行迁移文件,确保数据被正确转换为符合DecimalField要求的格式。

内容的提问来源于stack exchange,提问作者Lev Kakalashvili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:05:26