I have some Django models that use djmoney.models.fields.MoneyField. This stores data like "US$1,000.00".
I'm trying to expose this via an API with Django REST Framework directly in Django's admin with a custom view like:
from rest_framework import generics
from rest_framework import serializers
class MyModelAdmin(admin.ModelAdmin):
def changelist_view_api(self, request, extra_context=None):
cl = self.get_changelist_instance(request)
base_queryset = cl.get_queryset(request)
fieldsets = self.get_fieldsets(request)
class ModelSerializer(serializers.ModelSerializer):
class Meta:
model = self.model
fields = all_fields
class ModelAdminListAPI(generics.ListCreateAPIView):
queryset = base_queryset
serializer_class = ModelSerializer
name = '%s List API' % self.model._meta.verbose_name.title()
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
view_handler = ModelAdminListAPI.as_view(queryset=base_queryset, serializer_class=ModelSerializer)
return view_handler(request, extra_context, format=_format)
This works well, with the only exception that it chokes on these special MoneyField instances. With one of these in the field list, this view returns the exception:
File "~/.env/lib/python3.7/site-packages/rest_framework/mixins.py", line 43, in list
return self.get_paginated_response(serializer.data)
File "~/.env/lib/python3.7/site-packages/rest_framework/serializers.py", line 761, in data
ret = super().data
File "~/.env/lib/python3.7/site-packages/rest_framework/serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "~/.env/lib/python3.7/site-packages/rest_framework/serializers.py", line 679, in to_representation
self.child.to_representation(item) for item in iterable
File "~/.env/lib/python3.7/site-packages/rest_framework/serializers.py", line 679, in <listcomp>
self.child.to_representation(item) for item in iterable
File "~/.env/lib/python3.7/site-packages/rest_framework/serializers.py", line 530, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "~/.env/lib/python3.7/site-packages/rest_framework/fields.py", line 1148, in to_representation
value = decimal.Decimal(str(value).strip())
decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]
Digging into DRF's internals, it appears it's treating the MoneyField as a DecimalField, since that's what it inherits from. However, djmoney also creates another CharField called *_currency that stores the currency denomination (e.g. "USD"). Then, when you request the logical value for the money field, it combines the decimal and currency values into the format "".
I think DRF is running into a problem where it's trying to interpret this value as a decimal.
Is this a bug in DRF or do I have it misconfigured? How do I allow DRF to properly interpret MoneyField values?