How to get and process Input for django-multiselectfield in Django rest framework via form-data

3.2k views Asked by At

I have User model with food_prefrence field for which a user has the option to select multiple choices.

In models, I am using MultiSelectField from django-multiselectfield to solve my problem. and in my User serializer, I am using fields.MultipleChoiceField provided by rest-framework.

now my problem is how to get input from the user using form-data and how to process that in my view or serializer, as of now when I am trying to insert choices using postman with form-data selected, this is giving me an error when serializer.is_valid() is called

{
    "food_preference": [
        "\"'Indian', 'Continental'\" is not a valid choice."
    ]
}

below is my code snippet.

#models.py
class User(AbstractUser, BaseClass):
    food_preference = MultiSelectField(_('Food Preference'), choices=CONST_Food, blank=True, null=True)

#serializer.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
    food_preference = fields.MultipleChoiceField(choices=CONST_Food, required=False)

def update(self, instance, validated_data):
    instance.food_preference = validated_data.get('food_preference', instance.food_preference)
    instance.save()
    return instance, "Updated Successfully"

#views.py
def update(self, request, *args, **kwargs):
    instance = self.get_object()
    serializer = self.serializer_class(data=request.data, context={"request": self.request})
    print(serializer.initial_data)
    if serializer.is_valid(raise_exception=True): ##<<<<<Execution stops here
        print("is valid")
        result = serializer.update(instance=instance, validated_data=request.data)
        if result[0] is None:
            return _error_response(400, EPHISH, result[1], {})
        data = self.serializer_class(result[0], context={"request": self.request}).data
        return _response(data, status.HTTP_201_CREATED)
    else:
        return _einval_serializer_response(status.HTTP_400_BAD_REQUEST, self.serializer_class)

also here is the screenshot from my postman enter image description here

3

There are 3 answers

5
urDMG On

If you have something like

CONST_Food= (
        (1, 'One'),
        (2, 'Two'),
        (3, 'Three')
    )

Then you have to send 1,2,3.

<select multiple>
  <option value="1">One</option>
  <option value="2">Two</option>
  <option value="3">Three</option>
</select>

So the idea is to send values.

Update

Oh, finally I got this! You are using django-multiselectfield (please add it to the tags, so if someone will have the same problem he will find the solution faster) I've replicated your configuration and first of all instead of

CONST_Food= (
            (1, 'One'),
            (2, 'Two'),
            (3, 'Three')
        )

your tuple have to look like

CONST_Food= (
            ('1', 'One'),
            ('2', 'Two'),
            ('3', 'Three')
        )

The problem was in the serializer that expects list of strings, but you was sending the list of integers and/or values itself that it can't parse. So your JSON will be

{
...
    "food_preference": ["1", "3"]
...
}
1
jakobdo On

I had the same problem. And in DRF i changed the field to:

food_preference = fields.CharField(required=False)

Then i was good to go.

1
Safarbek On
from rest_framework import serializers
from yourapp.models import YourModel

class YourModelSerializer(serializers.ModelSerializer):
    your_multiselect_field = serializers.MultipleChoiceField(choices=YourModel.YOUR_CHOICES)

    class Meta:
        model = YourModel
        fields = '__all__'

List item