Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular dependency in serializers

I play with django-rest-framework and I would do following:

from rest_framework import serializers

from .models import Author, Book


class BookSerializer(serializers.ModelSerializer):
    author = AuthorSerializer(many=False)

    class Meta:
        model = Book
        fields = ('slug', 'name')


class AuthorSerializer(serializers.ModelSerializer):
    books = BookSerializer(many=True)

    class Meta:
        model = Author
        fields = ('slug', 'name', 'books')

But it fails.

NameError at /api/books/authors/
name 'AuthorSerializer' is not defined

Anybody helps?

like image 952
Tom Tichý Avatar asked Mar 23 '14 12:03

Tom Tichý


People also ask

Is it necessary to use Serializers in Django?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

What is the use of Serializers?

Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON , XML or other content types.

What is difference between serializer and ModelSerializer?

The ModelSerializer class is the same as a regular Serializer class, except that: It will automatically generate a set of fields for you, based on the model. It will automatically generate validators for the serializer, such as unique_together validators. It includes simple default implementations of .

What is meta class in serializer?

Serializer classes can also include reusable validators that are applied to the complete set of field data. These validators are included by declaring them on an inner Meta class. Also when you are defining a serializer then meta tags will help the serializer to bind that object in the specified format.


2 Answers

When the file is imported, it's content is executed from top to bottom. So the line author = AuthorSerializer(many=False) tries to instantiate the AuthorSerializer class before it is defined.

Even if you could fix the circular dependency problem, it would be bad design. Whenever you serialize an Author, you include a list of all his books, which in turn include the Author object with it's list of books. This will result in another error for exceeding the recursion depth limit.

What you need to decide is in which direction you want to keep the included serialization: do you want the full Author object in each book serialization, or do you want the list of books with all its information for each Author object?

The reverse relation can then be included using any form of RelatedField as provided by the Django REST Framework.

like image 94
knbk Avatar answered Oct 03 '22 09:10

knbk


I know the question is pretty old, but I found a simple solution.

You need to define auxiliary serializers to handle the reference both ways:

class BookUnrelatedSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ('slug', 'name')


class AuthorUnrelatedSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = ('slug', 'name')


class BookSerializer(BookUnrelatedSerializer):
    author = AuthorUnrelatedSerializer()

    class Meta(BookUnrelatedSerializer.Meta):
        fields = (*BookUnrelatedSerializer.Meta.fields, 'author')


class AuthorSerializer(AuthorUnrelatedSerializer):
    book_set = BookUnrelatedSerializer(many = True)

    class Meta(AuthorUnrelatedSerializer.Meta):
        fields = (*AuthorUnrelatedSerializer.Meta.fields, 'book_set')

This way you can use BookSerializer and AuthorSerializer without infinite circular dependency of a Book having an Author who has Books which have Author who has Books...

like image 11
Fidd Avatar answered Oct 03 '22 10:10

Fidd