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.
Command line execution
sed 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 erroRisk level: destructive. Review the command before running it.
Implementation details
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.
Gotchas and common issues
Permission checks - verify user access rights and sudo privileges before executing system-level operations.
Environment configuration - double-check path variables and dependency versions to prevent runtime failures.
Backup safeguards - maintain configuration backups before applying system or database modifications.
Following these steps ensures clean configuration and reliable execution for solved: {“non_field_errors”: [“expected a list of items but got type “dict”.”]}.
Comments and corrections