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

如何在Django自定义CurrencyField中实现模型层去除尾随零?

问题描述

希望在Django模型层面(而非模板或视图)去除模型字段的多余尾随零,现有代码如下:

现有模型类

class mycls(BaseModel):
    price = models.DecimalField()

自定义CurrencyField类

class CurrencyField(models.DecimalField):
    INTEGER_PLACES = 15
    DECIMAL_PLACES = 18

    DECIMAL_PLACES_FOR_USER = 6

    MAX_DIGITS = INTEGER_PLACES + DECIMAL_PLACES

    MAX_VALUE = Decimal('999999999999999.999999999999999999')
    MIN_VALUE = Decimal('-999999999999999.999999999999999999')

    def __init__(self, verbose_name=None, name=None, max_digits=MAX_DIGITS,
                 decimal_places=DECIMAL_PLACES, **kwargs):
        super().__init__(verbose_name=verbose_name, name=name, max_digits=max_digits,
                         decimal_places=decimal_places, **kwargs)

尾随零处理函数

def normalize_fraction(d):
    normalized = d.normalize()
    sign, digit, exponent = normalized.as_tuple()
    return normalized if exponent <= 0 else normalized.quantize(1)

需要实现:在上述自定义CurrencyField类中使用该函数,实现模型层自动去除字段值的多余尾随零。


解决方案

要在模型层面实现自动去除尾随零,需重写Django字段的值转换与预处理方法,确保在赋值、读取、存储三个环节都应用规范化函数。具体修改后的代码如下:

from decimal import Decimal

def normalize_fraction(d):
    normalized = d.normalize()
    sign, digit, exponent = normalized.as_tuple()
    return normalized if exponent <= 0 else normalized.quantize(1)

class CurrencyField(models.DecimalField):
    INTEGER_PLACES = 15
    DECIMAL_PLACES = 18

    DECIMAL_PLACES_FOR_USER = 6

    MAX_DIGITS = INTEGER_PLACES + DECIMAL_PLACES

    MAX_VALUE = Decimal('999999999999999.999999999999999999')
    MIN_VALUE = Decimal('-999999999999999.999999999999999999')

    def __init__(self, verbose_name=None, name=None, max_digits=MAX_DIGITS,
                 decimal_places=DECIMAL_PLACES, **kwargs):
        super().__init__(verbose_name=verbose_name, name=name, max_digits=max_digits,
                         decimal_places=decimal_places, **kwargs)

    def to_python(self, value):
        # 处理外部传入的值(如表单输入、直接赋值)
        value = super().to_python(value)
        if value is not None:
            return normalize_fraction(value)
        return value

    def from_db_value(self, value, expression, connection):
        # 处理从数据库读取的值
        value = super().from_db_value(value, expression, connection)
        if value is not None:
            return normalize_fraction(value)
        return value

    def pre_save(self, model_instance, add):
        # 存入数据库前最后一次规范化,确保存储值无冗余尾随零
        value = super().pre_save(model_instance, add)
        if value is not None:
            normalized_value = normalize_fraction(value)
            setattr(model_instance, self.attname, normalized_value)
            return normalized_value
        return value

关键逻辑说明

  • to_python:将外部原始值(字符串、整数等)转换为Decimal类型后,立即规范化,保证赋值给模型字段时已是无冗余尾随零的状态。
  • from_db_value:从数据库读取值时自动规范化,确保模型实例中存储的是处理后的值。
  • pre_save:在数据写入数据库前再次处理,彻底避免冗余尾随零被存入数据库。

内容的提问来源于stack exchange,提问作者Mehdi Aria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:25:50