Django Rest Framework - Serializer Method字段

Anu*_*nuj 8 python django django-rest-framework

使用序列化程序方法字段时,带有小数的字典将转换为整数.

例如.

class BillSerializer(serializers.ModelSerializer):
    bill_details = serializers.SerializerMethodField()

    class Meta:
        model = Bill
        fields = ('__all__')

    def get_bill_details(obj):
        return {'editable': False,
           'final_amt': Decimal('4198.00'),
           'total_amt': Decimal('4198.00'),
        }
Run Code Online (Sandbox Code Playgroud)

成为这个:

"bill_details": {
    "total_amt": 4198,
    "editable": false,
    "final_amt": 4198
  }
Run Code Online (Sandbox Code Playgroud)

这有什么解决方案吗?我期待这个:

"bill_details": {
    "total_amt": "4198.00",
    "editable": false,
    "final_amt": "4198.00"
}
Run Code Online (Sandbox Code Playgroud)

Sat*_*dra 6

Django REST Framework 3.0为您提供了的选择 serialize decimals as floats

现在,默认情况下,在序列化输出中,小数被强制转换为字符串。您可以使用COERCE_DECIMAL_TO_STRING设置键来全局修改此行为。

REST_FRAMEWORK = {
    'COERCE_DECIMAL_TO_STRING': False
}
Run Code Online (Sandbox Code Playgroud)

或使用coerce_to_string关键字参数在单个序列化器字段上对其进行修改。

# Return `Decimal` instances in `serializer.data`, not strings.
amount = serializers.DecimalField(
    max_digits=10,
    decimal_places=2,
    coerce_to_string=False
)
Run Code Online (Sandbox Code Playgroud)

默认的JSON渲染器将返回un-coercedDecimal实例的float对象。这使您可以轻松地根据API设计需求在小数的字符串或浮点表示形式之间切换。

更新

如果您只想四舍五入以产生2位小数精度的字符串以显示给用户,则可以

def get_bill_details(obj):
    return {
       'editable': False,
       'final_amt': '%.2f' %  Decimal('4198.00'),
       'total_amt': '%.2f' %  Decimal('4198.00'),
    }
Run Code Online (Sandbox Code Playgroud)

更新2

您可以使用自定义JSONEncoder类将其设置为DRY

创建一个DecimalEncoder类,继承json.JSONEncoder

from decimal import Decimal
import json

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return '%.2f' % obj
        return json.JSONEncoder.default(self, obj)
Run Code Online (Sandbox Code Playgroud)

现在在get_bill_details方法中使用此类

def get_bill_details(self, obj):
    bill_detail = {
        'editable': False,
        'final_amt': Decimal('4198.00'),
        'total_amt': Decimal('4198.00'),
    }
    return json.loads(json.dumps(bill_detail, cls=DecimalEncoder))
Run Code Online (Sandbox Code Playgroud)


Moh*_*ati 1

它变成了整数4198.00 == 4198,因为如果你想保留00,你应该使用str

如果你喜欢在一个点之后只出现2个整数,你可以使用格式(就像harri所说的那样format(obj.total_amt,'.2f'),但结果应该是一个字符串(就像你在预期结果中所说的那样)

class BillSerializer(serializers.ModelSerializer):
    bill_details = serializers.SerializerMethodField()

    class Meta:
        model = Bill
        fields = ('__all__')

    def get_bill_details(self, obj):
        return {'editable': False,
           'final_amt': str(Decimal('4198.00')),
           'total_amt': str(Decimal('4198.00')),
        }
Run Code Online (Sandbox Code Playgroud)