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

如何用Django自定义字段存储Decimal并返回整数及原始值?

Yes, a Custom Django Model Field Is Exactly What You Need

Your approach is on the right track, but the initial code has a few gaps to meet your exact requirements. Let's fix that by building a field that stores raw Decimal values, returns a rounded integer when accessed directly, and exposes the original value via a get_raw() method.

Step-by-Step Solution

First, we'll create a wrapper class to hold both the raw Decimal value and the rounded integer. This wrapper will behave like an integer in most contexts while keeping the raw value accessible:

import decimal

class RoundedDecimalWrapper:
    def __init__(self, raw_value):
        self.raw_value = raw_value
        self.rounded_value = int(round(raw_value))
    
    # Make the wrapper act like an integer in common operations
    def __int__(self):
        return self.rounded_value
    
    def __float__(self):
        return float(self.rounded_value)
    
    def __str__(self):
        return str(self.rounded_value)
    
    def __repr__(self):
        return f"RoundedDecimalWrapper(raw={self.raw_value}, rounded={self.rounded_value})"
    
    # Method to retrieve the original Decimal value
    def get_raw(self):
        return self.raw_value

Next, we'll build the custom model field that uses this wrapper. This field inherits from DecimalField to handle database storage correctly, and overrides key methods to manage value conversion:

from django.db import models
from django.core.exceptions import ValidationError

class MyField(models.DecimalField):
    def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
        # Pass all parameters to the parent DecimalField correctly
        super().__init__(
            verbose_name=verbose_name,
            name=name,
            max_digits=max_digits,
            decimal_places=decimal_places,
            **kwargs
        )
    
    def to_python(self, value):
        # Let the parent class handle converting input to a Decimal first
        decimal_value = super().to_python(value)
        
        if decimal_value is None:
            return None
        
        # Wrap the raw Decimal in our custom class
        return RoundedDecimalWrapper(decimal_value)
    
    def get_prep_value(self, value):
        # When saving to the database, use the raw Decimal value
        if isinstance(value, RoundedDecimalWrapper):
            return value.raw_value
        # For other cases (e.g., initial assignment), defer to the parent method
        return super().get_prep_value(value)

How It Works

  1. Storage: The field uses DecimalField under the hood, so your raw numeric values are stored as Decimals in the database (preserving full precision).
  2. Accessing the Rounded Value: When you access mymodel.myfield, you get a RoundedDecimalWrapper instance. Thanks to the magic methods (__int__, __str__, etc.), it behaves like the rounded integer in most scenarios:
    obj = MyModel(myfield=12.61)
    obj.save()
    print(obj.myfield)  # Output: 13
    print(obj.myfield + 7)  # Output: 20 (implicitly uses __int__)
    
  3. Retrieving the Raw Value: Call get_raw() on the field value to get the original Decimal:
    print(obj.myfield.get_raw())  # Output: Decimal('12.61')
    

Key Notes

  • Validation: The parent DecimalField handles all standard validation (e.g., ensuring values fit within max_digits and decimal_places), so you don’t need to reimplement that logic.
  • Querying: If you need to filter based on the rounded value, use Django's database functions to round the field in your query (since the database stores the raw Decimal):
    from django.db.models.functions import Round
    MyModel.objects.annotate(rounded_myfield=Round('myfield')).filter(rounded_myfield=13)
    
  • Wrapper Behavior: The current wrapper covers basic use cases, but you can add more magic methods (like __add__, __lt__) if you need full integer-like behavior for advanced operations.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:22:17