axnsan12 / drf-yasg

Automated generation of real Swagger/OpenAPI 2.0 schemas from Django REST Framework code.
https://drf-yasg.readthedocs.io/en/stable/
Other
3.42k stars 439 forks source link

DecimalField TypeError [Help Wanted] #340

Closed amandeep-r closed 5 years ago

amandeep-r commented 5 years ago

Hello,

I'm getting the following Type Error after I added a decimal field to my model:

Decimal('50') is not JSON serializable

I'm using Django version 2.1.7 and drf_yasg version 1.14.0. I looked into setting COERCE_DECIMAL_TO_STRING in my DRF setting to true but no luck. There was a similar issue (#62 ) earlier but I was unable to use that information to help with my current issue.

Here is my traceback:


Environment:

Request Method: GET
Request URL: http://api.dev-babylon.com/api/swagger/?format=openapi

Django Version: 2.1.7
Python Version: 3.5.2
Installed Applications:
['corsheaders',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django_extensions',
 'django_filters',
 'rest_framework',
 'rest_framework.authtoken',
 'rest_auth',
 'mysite.babylon.apps.BabylonConfig',
 'mysite.consumables.apps.ConsumablesConfig',
 'django_celery_beat',
 'drf_yasg']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware']

Traceback:

File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py" in _get_response
  156.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py" in _get_response
  154.                 response = response.render()

File "/usr/local/lib/python3.5/dist-packages/django/template/response.py" in render
  106.             self.content = self.rendered_content

File "/usr/local/lib/python3.5/dist-packages/rest_framework/response.py" in rendered_content
  72.         ret = renderer.render(self.data, accepted_media_type, context)

File "/usr/local/lib/python3.5/dist-packages/drf_yasg/renderers.py" in render
  37.         return codec.encode(data)

File "/usr/local/lib/python3.5/dist-packages/drf_yasg/codecs.py" in encode
  84.         return force_bytes(self._dump_dict(spec))

File "/usr/local/lib/python3.5/dist-packages/drf_yasg/codecs.py" in _dump_dict
  127.             return json.dumps(spec)

File "/usr/lib/python3.5/json/__init__.py" in dumps
  230.         return _default_encoder.encode(obj)

File "/usr/lib/python3.5/json/encoder.py" in encode
  198.         chunks = self.iterencode(o, _one_shot=True)

File "/usr/lib/python3.5/json/encoder.py" in iterencode
  256.         return _iterencode(o, 0)

File "/usr/lib/python3.5/json/encoder.py" in default
  179.         raise TypeError(repr(o) + " is not JSON serializable")

Exception Type: TypeError at /api/swagger/
Exception Value: Decimal('50') is not JSON serializable
axnsan12 commented 5 years ago

Can you provide an example of a problematic serializer/view?

amandeep-r commented 5 years ago

Sure,

So here is the relevant part of my model:

class Pack(models.Model):
    SIZE_10x20 = Decimal(200.000)
    SIZE_10x10 = Decimal(100.000)
    SIZE_5x10 = Decimal(50.000)

    size_code_choices = (
        (SIZE_5x10, '5x10'),
        (SIZE_10x10, '10x10'),
        (SIZE_10x20, '10x20'),
    )
    size_code = models.DecimalField(max_digits=7,
                                    decimal_places=3,
                                    choices=size_code_choices,
                                    default=SIZE_10x20)

The serializer:

class HarvestSerializer(serializers.ModelSerializer):
    harvest_signal = serializers.BooleanField(required=True, write_only=True)

    class Meta:
        model = Pack
        fields = (
            'harvest_signal',
            'pack_uuid',
            'size_code'
        )
        read_only_fields = (
            'pack_uuid',
            'size_code'
        )

And the viewset:

class HarvestViewSet(mixins.ListModelMixin,
                     mixins.UpdateModelMixin,
                     viewsets.GenericViewSet):

    queryset = Pack.objects.all()
    serializer_class = HarvestSerializer
    permission_classes = [permissions.IsAuthenticated, api_permissions.HarvestPermissions]
    authentication_classes = [TokenAuthentication]

    def perform_update(self, serializer):
        instance = serializer.instance
        logger.debug("Performing Update!")
        if serializer.validated_data['harvest_signal'] is True:
            #Business Logic Here ---
        else:
            pass
        serializer.save()

Appreciate the speedy reply!

amandeep-r commented 5 years ago

I have other models and serializers that use DecimalFields. I highly suspect it has something to do with the choices constraint on this particular model field.