from django.db import models
from extended_choices import Choices
choices = Choices(
("C1", 0, "Choice 1"),
("C2", 1, "Choice 2")
)
class TestModel(models.Model):
test_field = models.IntegerField(
choices = choices, default = choices.C1
)
drf-spectacular is unable to serialize the schema of this model because the choices are of type extended_choices.helpers.IntChoiceAttribute and not raw integers.
➜ ./manage.py spectacular --file schema.yml
Traceback (most recent call last):
File "./manage.py", line 22, in <module>
main()
File "./manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "test_spectacular/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "test_spectacular/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "test_spectacular/venv/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv
self.execute(*args, **cmd_options)
File "test_spectacular/venv/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute
output = self.handle(*args, **options)
File "test_spectacular/venv/lib/python3.8/site-packages/drf_spectacular/management/commands/spectacular.py", line 60, in handle
output = renderer.render(schema, renderer_context={})
File "test_spectacular/venv/lib/python3.8/site-packages/drf_spectacular/renderers.py", line 26, in render
return yaml.dump(
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/__init__.py", line 290, in dump
return dump_all([data], stream, Dumper=Dumper, **kwds)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/__init__.py", line 278, in dump_all
dumper.represent(data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 27, in represent
node = self.represent_data(data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 48, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 207, in represent_dict
return self.represent_mapping('tag:yaml.org,2002:map', data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 118, in represent_mapping
node_value = self.represent_data(item_value)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 48, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 207, in represent_dict
return self.represent_mapping('tag:yaml.org,2002:map', data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 118, in represent_mapping
node_value = self.represent_data(item_value)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 48, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 207, in represent_dict
return self.represent_mapping('tag:yaml.org,2002:map', data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 118, in represent_mapping
node_value = self.represent_data(item_value)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 48, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 207, in represent_dict
return self.represent_mapping('tag:yaml.org,2002:map', data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 118, in represent_mapping
node_value = self.represent_data(item_value)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 48, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 199, in represent_list
return self.represent_sequence('tag:yaml.org,2002:seq', data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 92, in represent_sequence
node_item = self.represent_data(item)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 58, in represent_data
node = self.yaml_representers[None](self, data)
File "test_spectacular/venv/lib/python3.8/site-packages/yaml/representer.py", line 231, in represent_undefined
raise RepresenterError("cannot represent an object", data)
yaml.representer.RepresenterError: ('cannot represent an object', 0)
I can solve that by overriding the serializer field and providing a standard default by casting to int, but it's a little annoying to do that for each ChoiceField.
Django/DRF are able to work that out (that it's in fact an int, above code works out of the box in the admin and in serializers) so maybe drf-spectacular could as well?
from .models import TestModel
from rest_framework import viewsets
from rest_framework import serializers
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = TestModel
fields = ['id', 'test_field']
class TestViewSet(viewsets.ModelViewSet):
queryset = TestModel.objects.all()
serializer_class = TestSerializer
Describe the bug
I have a model with a field that has a
choicesparameter. This parameter is not a standard list of tuples but a django-extended-choices Choices class:drf-spectacular is unable to serialize the schema of this model because the choices are of type
extended_choices.helpers.IntChoiceAttributeand not raw integers.Schema generation fails as follow:
This is the value of
data_typesin last frame:(<class 'extended_choices.helpers.IntChoiceAttribute'>, <class 'extended_choices.helpers.ChoiceAttributeMixin'>, <class 'int'>, <class 'object'>)As this is not a custom field, I cannot use
OpenApiSerializerFieldExtension.I can solve that by overriding the serializer field and providing a standard default by casting to int, but it's a little annoying to do that for each ChoiceField.
Django/DRF are able to work that out (that it's in fact an int, above code works out of the box in the admin and in serializers) so maybe drf-spectacular could as well?
To Reproduce
In addition to above snippet, you can use this view:
Expected behavior
I want the extended choices object to be properly serialized as an Enum.