Developers working with Django REST Framework (DRF) often encounter serialization issues when handling nested objects or ManyToMany relationships in APIs. One of the common errors is: “{“non_field_errors”: [“Expected a list of items but got type “dict”.”]}”. This error typically arises when DRF expects a list of items but instead receives a dictionary. Understanding why this happens and how to fix it ensures smoother API development and prevents data serialization issues.
Understanding the Error: Why Does Django REST Framework Expect a List?
🔹 Django REST Framework serializers are designed to handle different types of data structures, including single objects, lists of objects, and nested relationships.
🔹 When using a ManyToManyField or ForeignKey with a nested serializer, DRF expects a list of objects for ManyToMany fields but a dictionary for ForeignKey fields.
🔹 If the API receives a dictionary instead of a list where a ManyToMany field is expected, it triggers the error: “Expected a list of items but got type “dict”.”
🔹 This issue commonly occurs when working with nested serializers, bulk data submissions, or incorrect request payload formatting.
Identifying whether the issue is caused by incorrect serializer definitions or request payload structure is the first step toward solving it.
How to Fix the “Expected a List of Items but Got Type Dict” Error?
Consider a ManyToMany relationship where an Author
can have multiple Books
, as defined in models.py:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=255)
class Author(models.Model):
name = models.CharField(max_length=255)
books = models.ManyToManyField(Book)
In the corresponding serializers.py, using a nested serializer without setting many=True
will cause the error:
from rest_framework import serializers
from .models import Book, Author
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer()
class Meta:
model = Author
fields = '__all__'
If an API request is made with the following payload:
{
"name": "John Doe",
"books": {"title": "Django for Beginners"}
}
DRF will return the error “Expected a list of items but got type “dict”.” because books
is a ManyToManyField and expects a list.
Correcting the Serializer to Accept a List of Items
To allow multiple books for an author, modify books
in the AuthorSerializer
by adding many=True
:
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True)
class Meta:
model = Author
fields = '__all__'
Now, when making an API request, ensure the payload sends books
as a list of objects:
{
"name": "John Doe",
"books": [
{"title": "Django for Beginners"},
{"title": "Advanced Django"}
]
}
This modification ensures that Django correctly processes multiple book instances without triggering the error.
Handling ManyToMany Relationships with Primary Keys Instead of Nested Objects
If the API should accept only book IDs instead of full objects, use the PrimaryKeyRelatedField instead of a nested serializer:
class AuthorSerializer(serializers.ModelSerializer):
books = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all(), many=True)
class Meta:
model = Author
fields = '__all__'
With this change, the API request should send only book IDs instead of full objects:
{
"name": "John Doe",
"books": [1, 2]
}
This approach is more efficient for large datasets where book details do not need to be sent with the request.
Common Issues and Troubleshooting
1. Error Persists Even After Adding many=True
✔ Ensure that the API request payload correctly sends a list of objects instead of a dictionary.
✔ Double-check that many=True
is applied only for ManyToMany relationships and not for ForeignKey fields.
✔ Restart the Django server after modifying serializers to ensure changes are applied.
2. Unable to Save Nested Data for ManyToMany Relationships
✔ Overriding the create()
method ensures that nested objects are properly created:
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True)
class Meta:
model = Author
fields = '__all__'
def create(self, validated_data):
books_data = validated_data.pop('books')
author = Author.objects.create(**validated_data)
for book_data in books_data:
book, created = Book.objects.get_or_create(**book_data)
author.books.add(book)
return author
✔ This allows new books to be created and associated with the author dynamically.
3. Using a ForeignKey Instead of ManyToMany But Still Facing the Error
✔ Many developers mistakenly apply many=True
to ForeignKey fields, causing unintended errors.
✔ ForeignKey relationships expect a single dictionary, whereas ManyToMany relationships require lists of dictionaries.
class ChapterSerializer(serializers.ModelSerializer):
book = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all())
class Meta:
model = Chapter
fields = '__all__'
✔ The request should send only a single book ID:
{
"title": "Chapter One",
"content": "Introduction to Django",
"book": 1
}
Why Understanding Serializer Structures in DRF is Important?
🔹 Ensures data consistency and prevents serialization errors when handling nested relationships.
🔹 Helps developers optimize API requests, reducing payload size and improving performance.
🔹 Allows flexible data structures, enabling APIs to handle both nested and primary key-based relationships effectively.
🔹 Prevents common Django REST Framework mistakes, improving overall backend efficiency.
By structuring serializers correctly and sending API requests in the expected format, developers can avoid errors and enhance the stability of Django applications.
The error “Expected a list of items but got type “dict”.” occurs when Django REST Framework expects a list for ManyToMany relationships but receives a dictionary instead. By correctly defining serializers using many=True and ensuring API requests follow the correct format, this issue can be resolved easily. Whether using nested objects or primary keys, structuring API requests properly is crucial for smooth data serialization and efficient relationship handling.
Start implementing best practices in Django REST Framework today and enhance API efficiency and error handling!