简体   繁体   中英

Django REST framework - MultiSelectField - TypeError: Object of type 'set' is not JSON serializable

I'm trying to make a multi-choice rest api with Django REST framework and django-multiselectfield .

Currently inside the model I have:

ANIMAL = (
    ('dog', 'Dog'),
    ('cat', 'Cat'),
)

class MyForm(models.Model):
    ...
    animals = MultiSelectField(choices=ANIMAL)

and in my serializer I have:

class MyFormSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyForm
        fields = (..., 'animals')

    animals = fields.MultipleChoiceField(choices=ANIMAL)

When I'm trying to POST into the api using this kind of body:

{
    ...
    "animals": ["cat"],
    ...
}

I get an error: TypeError: Object of type 'set' is not JSON serializable

Traceback (most recent call last):
  File "C:\Python36\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Python36\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Python36\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Python36\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "c:\mysite\myserver\myform\views.py", line 15, in angels_add
    return JsonResponse(serializer.data, status=201)
  File "C:\Python36\lib\site-packages\django\http\response.py", line 558, in __init__
    data = json.dumps(data, cls=encoder, **json_dumps_params)
  File "C:\Python36\lib\json\__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "C:\Python36\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Python36\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Python36\lib\site-packages\django\core\serializers\json.py", line 104, in default
    return super().default(o)
  File "C:\Python36\lib\json\encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'set' is not JSON serializable

Though, the form is submitted and I can see the entire data in the admin panel succesfully (?).

I'm using the following versions:

  • Django==2.2.1
  • djangorestframework==3.9.3
  • django-multiselectfield==0.1.8

any idea why I get this exception?

also, I can switch from multiselectfield to another technology if something else would work and will allow me to add multiple choice fields which I can filter later from the admin panel

class MyFormAdmin(admin.ModelAdmin):
    list_filter = (
        'animals',
        ...
    )

I've read about ArrayField , but I'm not happy with a solution that fit only one kind of db (postgres) as I might use another.

Thanks in advance,

Etay.

From the source code , the to_representation() method of MultipleChoiceField returns data as set

Create a custom MultipleChoiceField class and use it in your serializer

class CustomMultipleChoiceField(fields.MultipleChoiceField):
    def to_representation(self, value):
        return list(super().to_representation(value))
class MyFormSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyForm
        fields = (..., 'animals')

    animals = 

JPG's solution might work in some cases, but is not really rugged. (also depends on your use case)

A more low level way of solving this, is by extending the JSONEncoder or even better DjangoJSONEncoder (which is already extended) and using it. This way, you only have to implement it ones.

class CustomJSONEncoder(DjangoJSONEncoder):
    """
    Custom encoder that also supports `set`, since we require this for
    saving the `MultipleChoiceField`.
    """

    def default(self, obj):
        if isinstance(obj, set):
            return list(obj)
        return super().default(obj)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM