如何为Python序列化器批量设置Decimal上下文精度?
问题描述
我编写了如下Python序列化器代码:
from decimal import Decimal, setcontext, getcontext class MyNewSerializer(serializers.Serializer): total_value_base = serializers.SerializerMethodField() total_outgoing_value_base = serializers.DecimalField( max_digits=38, decimal_places=8, source="value_sent", ) total_incoming_value = serializers.DecimalField( max_digits=38, decimal_places=4, source="value_received", ) def get_total_value_base(self, obj): total = Decimal(obj.value_received) + Decimal( obj.value_sent ) # Values of above objects # obj.value_received = 425933085766969760747388.45622168 # obj.value_sent = 0 # total = 425933085766969760747388.4562 dec = Decimal(str(total)) return round(dec, 8)
运行时抛出错误:
return round(dec, 8) decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
添加getcontext().prec = 100后问题解决:
def get_total_value_base(self, obj): # the below line fixes the issue getcontext().prec = 100 total = Decimal(obj.value_received) + Decimal( obj.value_sent ) # Values of above objects # obj.value_received = 425933085766969760747388.45622168 # obj.value_sent = 0 # total = 425933085766969760747388.4562 dec = Decimal(str(total)) return round(dec, 8)
现在需要为当前类及其他同类序列化器中的所有Decimal值提升精度,涉及文件中多个类的上百个变量。请问如何通过基类或重写Decimal类实现全局/批量设置?
解决方案
以下是几种批量提升Decimal精度的可行方案:
1. 自定义基础序列化器基类
创建一个基类,在初始化时设置Decimal上下文精度,所有需要提升精度的序列化器都继承这个基类:
from decimal import getcontext from rest_framework import serializers class HighPrecisionSerializer(serializers.Serializer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 设置全局Decimal精度,覆盖默认的28位 getcontext().prec = 100 # 原有序列化器继承这个基类即可 class MyNewSerializer(HighPrecisionSerializer): total_value_base = serializers.SerializerMethodField() total_outgoing_value_base = serializers.DecimalField( max_digits=38, decimal_places=8, source="value_sent", ) # ... 其他字段保持不变 def get_total_value_base(self, obj): total = Decimal(obj.value_received) + Decimal(obj.value_sent) dec = Decimal(str(total)) return round(dec, 8)
所有继承HighPrecisionSerializer的类都会自动应用高精度设置,无需在每个方法中重复编写精度配置代码。
2. 自定义高精度DecimalField
如果只需要针对DecimalField字段提升精度,可以自定义一个HighPrecisionDecimalField替换原有字段:
from decimal import getcontext from rest_framework import serializers class HighPrecisionDecimalField(serializers.DecimalField): def to_internal_value(self, data): # 转换前设置精度 getcontext().prec = 100 return super().to_internal_value(data) def to_representation(self, value): # 序列化输出时保持高精度 getcontext().prec = 100 return super().to_representation(value) # 使用自定义字段替换原有DecimalField class MyNewSerializer(serializers.Serializer): total_value_base = serializers.SerializerMethodField() total_outgoing_value_base = HighPrecisionDecimalField( max_digits=38, decimal_places=8, source="value_sent", ) total_incoming_value = HighPrecisionDecimalField( max_digits=38, decimal_places=4, source="value_received", ) # ... 其他方法不变
这种方式精准控制所有Decimal字段的精度处理,适合无需全局修改Serializer、仅针对字段调整的场景。
3. 全局设置Decimal上下文
如果希望整个项目的Decimal操作都使用高精度,可在项目启动时(如settings.py或入口文件)设置全局精度:
# 在项目初始化文件中添加 from decimal import getcontext getcontext().prec = 100
该方式最简单,一次性设置后所有Decimal相关操作都会使用100位精度,无需修改任何序列化器代码。注意此设置会影响项目中所有Decimal运算,需确认不会引发其他问题。
4. 自定义Decimal子类(可选)
若需要更细粒度的控制,可自定义高精度Decimal子类,在序列化器中替代原生Decimal:
from decimal import Decimal, getcontext class HighPrecisionDecimal(Decimal): def __new__(cls, value="0", context=None): # 强制使用高精度上下文 ctx = getcontext() original_prec = ctx.prec ctx.prec = 100 instance = super().__new__(cls, value, context=ctx) ctx.prec = original_prec # 可选:恢复原有精度,避免影响其他代码 return instance # 在SerializerMethodField中使用自定义子类 def get_total_value_base(self, obj): total = HighPrecisionDecimal(obj.value_received) + HighPrecisionDecimal(obj.value_sent) dec = HighPrecisionDecimal(str(total)) return round(dec, 8)
此方式适合单独控制某些Decimal实例精度的场景,但替换上百个变量时,效率不如前几种方案。
内容的提问来源于stack exchange,提问作者Cool Breeze
相关产品推荐
相关产品推荐

