DRF ManyToMany Field getting an error when creating object
Question:
I have a Rant
model with Category
linked to it using ManyToManyField
. I’ve serialized it but the problem is this error:
{
"categories": [
"Expected a list of items but got type "str"."
]
}
These are my serializers:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
class RantSerializer(serializers.ModelSerializer):
categories = CategorySerializer(many=True)
class Meta:
model = Rant
fields = ('rant', 'slug', 'categories')
My post
method is this:
def post(self, request, format=None):
serializer = RantSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
What did I do wrong here?
Answers:
Currently you might be send a request with body something like this,
{
"rant": "This is my rant",
"slug": "my-rant",
"categories": 1
}
Since categories is a ManyToMany relation, it is expecting a list of ids,
Give this a try:
{
"rant": "This is my rant",
"slug": "my-rant",
"categories": [1, 2, 3]
}
The problem is with serializer, and your serializer is read-only, and threrefore serializer.save() has no effect.
In order to change this behavior, you need to overwrite serializer methods: create() and update(), or/and save().
Check this documentation for implementation details: https://www.django-rest-framework.org/api-guide/serializers/#saving-instances
I had faced a similar problem. Do the following to solve your issue
- Install the drf-writable-nested with
pip install drf-writable-nested
- Re-write your serializers like so
# --- snip ---
from drf_writable_nested.serializers import WritableNestedModelSerializer
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
class RantSerializer(WritableNestedModelSerializer):
categories = CategorySerializer(many=True)
class Meta:
model = Rant
fields = ('rant', 'slug', 'categories')
# ---snip ----
The catch here is to import and implement the WritableNestedModelSerializer
class. Also note that the serializers.ModelSerializer
super class has been replaced on the serializer where you want to do the nested payload.
- Trying performing the API calls. You should be good to go.
For more information, refer to this repo’s README here
I have a Rant
model with Category
linked to it using ManyToManyField
. I’ve serialized it but the problem is this error:
{
"categories": [
"Expected a list of items but got type "str"."
]
}
These are my serializers:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
class RantSerializer(serializers.ModelSerializer):
categories = CategorySerializer(many=True)
class Meta:
model = Rant
fields = ('rant', 'slug', 'categories')
My post
method is this:
def post(self, request, format=None):
serializer = RantSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
What did I do wrong here?
Currently you might be send a request with body something like this,
{
"rant": "This is my rant",
"slug": "my-rant",
"categories": 1
}
Since categories is a ManyToMany relation, it is expecting a list of ids,
Give this a try:
{
"rant": "This is my rant",
"slug": "my-rant",
"categories": [1, 2, 3]
}
The problem is with serializer, and your serializer is read-only, and threrefore serializer.save() has no effect.
In order to change this behavior, you need to overwrite serializer methods: create() and update(), or/and save().
Check this documentation for implementation details: https://www.django-rest-framework.org/api-guide/serializers/#saving-instances
I had faced a similar problem. Do the following to solve your issue
- Install the drf-writable-nested with
pip install drf-writable-nested
- Re-write your serializers like so
# --- snip ---
from drf_writable_nested.serializers import WritableNestedModelSerializer
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
class RantSerializer(WritableNestedModelSerializer):
categories = CategorySerializer(many=True)
class Meta:
model = Rant
fields = ('rant', 'slug', 'categories')
# ---snip ----
The catch here is to import and implement the WritableNestedModelSerializer
class. Also note that the serializers.ModelSerializer
super class has been replaced on the serializer where you want to do the nested payload.
- Trying performing the API calls. You should be good to go.
For more information, refer to this repo’s README here