Django Rest Framework - Serializer Method字段

时间:2016-08-09 11:17:32

标签: 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'),
        }

成为这个:

"bill_details": {
    "total_amt": 4198,
    "editable": false,
    "final_amt": 4198
  }

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

"bill_details": {
    "total_amt": "4198.00",
    "editable": false,
    "final_amt": "4198.00"
}

5 个答案:

答案 0 :(得分:6)

  

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

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

REST_FRAMEWORK = {
    'COERCE_DECIMAL_TO_STRING': False
}

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

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

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

更新

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

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

更新2

  

您可以使用自定义使其干燥   JSONEncoder 类。

创建一个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)

现在在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))

答案 1 :(得分:2)

您可以在SerializerMethodField中使用新的Serializer,如下所示:

from rest_framework import serializers

class BillDetailsSerializer(serializers.Serializer):
    editable = serializers.BooleanField()
    final_amt = serializers.DecimalField(decimal_places=2, max_digits=15)
    total_amt = serializers.DecimalField(decimal_places=2, max_digits=15)

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

    class Meta:
        model = Bill
        fields = '__all__'

     def get_bill_details(self, obj):
         data = {...} # your logic
         field_serializer = BillDetailsSerializer(data=data)
         field_serializer.is_valid() # this serializer must always valid
         return field_serializer.data

我认为这更加清楚,每个人都可以理解哪些字段具有bill_details

答案 2 :(得分:1)

由于4198.00 == 4198,如果要保留00,则应使用str

,它成为整数。

如果您只喜欢在一个点后加上2个整数,则可以使用格式(例如hardi所说的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')),
        }

答案 3 :(得分:1)

getItem

请尝试使用format()

答案 4 :(得分:0)

如果您不想对bill_details使用其他序列化器,那么<​​/ p>

from rest_framework import serializers
from decimal import Decimal

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

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

    def get_bill_details(obj):
        amount_field = DecimalField(max_digits=12, decimal_places=2)
        final_amt = Decimal('4198.00')
        total_amt = Decimal('4198.00')
        return {
            'editable': False,
            'final_amt': amount_field.to_representation(final_amt),
            'total_amt': amount_field.to_representation(total_amt),
        }