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

如何在Django模型保存时将美元字段自动转换为美分单位存储?

实现方案

方案1:使用@property装饰器(快速实现,无需自定义字段)

这是最轻量化的实现方式,通过Python原生的属性描述符实现存取自动转换:
首先修改模型字段定义,将原存储字段改为美分存储的底层字段,再通过property暴露美元单位的访问入口:

from django.db import models
from decimal import Decimal, ROUND_HALF_UP

class Bank(models.Model):
    backup = False
    device_type = models.BigIntegerField(verbose_name='device type')
    # 底层存储字段,存美分单位,不直接对外暴露
    _transaction_sum_cents = models.BigIntegerField(verbose_name='sum in cents', db_column='transaction_sum')
    
    @property
    def transaction_sum(self):
        """getter:从美分转美元"""
        return Decimal(self._transaction_sum_cents) / Decimal('100')
    
    @transaction_sum.setter
    def transaction_sum(self, value):
        """setter:从美元转美分,自动处理四舍五入避免精度问题"""
        if value is None:
            self._transaction_sum_cents = None
            return
        # 统一用Decimal处理金额,避免浮点数精度丢失
        dollar_value = Decimal(str(value))
        cent_value = int((dollar_value * Decimal('100')).quantize(Decimal('1'), rounding=ROUND_HALF_UP))
        self._transaction_sum_cents = cent_value

注意:如果需要基于金额做ORM查询,需要对_transaction_sum_cents字段做过滤,比如查询金额大于100美元的记录:Bank.objects.filter(_transaction_sum_cents__gt=100*100)

方案2:自定义模型字段(完全透明,推荐生产环境使用)

如果希望逻辑更封装、使用完全透明(和普通字段用法完全一致,包括ORM查询也直接支持美元单位),可以自定义金额转换字段,这是Django模型提供的标准扩展能力:

from django.db import models
from decimal import Decimal, ROUND_HALF_UP

class DollarToCentsField(models.BigIntegerField):
    def from_db_value(self, value, expression, connection):
        """从数据库取数据时自动转美元"""
        if value is None:
            return value
        return Decimal(value) / Decimal('100')
    
    def get_prep_value(self, value):
        """存数据时自动转美分"""
        if value is None:
            return value
        dollar_value = Decimal(str(value))
        cent_value = int((dollar_value * Decimal('100')).quantize(Decimal('1'), rounding=ROUND_HALF_UP))
        return cent_value

之后直接在模型中使用自定义字段即可,不需要额外修改其他逻辑:

class Bank(models.Model):
    backup = False
    device_type = models.BigIntegerField(verbose_name='device type')
    # 直接使用自定义字段,外部操作全是美元单位,自动完成存储转换
    transaction_sum = DollarToCentsField(verbose_name='sum in dollars')

该方案下ORM查询也可以直接用美元单位传参,比如Bank.objects.filter(transaction_sum__gt=100)会自动转换为美分的条件查询。

注意事项

  • 所有金额运算建议统一使用Decimal类型,避免浮点数精度丢失导致的金额错误
  • 如果模型需要支持update()批量更新,方案1需要手动转美分对_transaction_sum_cents赋值,方案2不受影响
  • 两种方案都不需要手动调用转换方法,所有对transaction_sum的赋值、取值操作都会自动完成单位换算。

内容的提问来源于stack exchange,提问作者Павел Иванов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 08:15:01