如何在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
相关产品推荐
相关产品推荐

