When using serializer method field, the dictionary with Decimals is converted to Integers.
For eg.
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'),
}
becomes this:
"bill_details": {
"total_amt": 4198,
"editable": false,
"final_amt": 4198
}
Is there any solution to this? I am expecting this:
"bill_details": {
"total_amt": "4198.00",
"editable": false,
"final_amt": "4198.00"
}
Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
to_representation(self, value) method. This method takes the target of the field as the value argument, and should return the representation that should be used to serialize the target. The value argument will typically be a model instance.
How do I pass Queryset to serializer? To serialize a queryset or list of objects instead of a single object instance, you should pass the many=True flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.
Django REST framework 3.0 gives you the option to
serialize decimals as floats
.
Decimals are now coerced to strings by default in the serialized output. You can modify this behavior globally by using the COERCE_DECIMAL_TO_STRING
settings key.
REST_FRAMEWORK = {
'COERCE_DECIMAL_TO_STRING': False
}
Or modify it on an individual serializer field, using the coerce_to_string
keyword argument.
# Return `Decimal` instances in `serializer.data`, not strings.
amount = serializers.DecimalField(
max_digits=10,
decimal_places=2,
coerce_to_string=False
)
The default JSON renderer will return float objects for un-coerced
Decimal instances. This allows you to easily switch between string or float representations for decimals depending on your API design needs.
UPDATE
If you want to just round it to produce a string with 2 decimal precision to display to the user, you can do
def get_bill_details(obj):
return {
'editable': False,
'final_amt': '%.2f' % Decimal('4198.00'),
'total_amt': '%.2f' % Decimal('4198.00'),
}
UPDATE 2
You can make it DRY, By using a custom JSONEncoder class.
Create a DecimalEncoder
class, inheriting 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)
Now Use this class inside get_bill_details
method
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))
You can use new Serializer in SerializerMethodField like so:
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
I think it is more clear and everyone can undestand what fields have bill_details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With