dawid
dawid

Reputation: 45

Django Rest Framework - problem with filtering data

in my models i have Book and Author with M2M relationship.

models.py

from django.db import models


from django.db import models


class Book(models.Model):
    title          = models.CharField(max_length=200)
    published_date = models.DateField(auto_now_add=False)
    categories     = models.CharField(max_length=300, null=True, blank=True)
    average_rating = models.FloatField(null=True, blank=True)
    ratings_count  = models.IntegerField(null=True, blank=True)
    thumbnail      = models.URLField(null=True, blank=True)

def authors(self):
    return self.author_set.all()

def __str__(self):
    return f'title: {self.title} \n' \
           f'date of publication: {self.published_date}'


class Author(models.Model):
    name  = models.CharField(max_length=200)
    books = models.ManyToManyField(Book)

    def __str__(self):
        return str(self.name)

in my serializer i'm getting authors from def authors in models.py

serializers.py
    class Meta:
        model = Author
        fields = ['name']


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

    class Meta:
        model = Book
        fields = [
            'authors',
            'title',
            'published_date',
            'categories',
            'average_rating',
            'ratings_count',
            'thumbnail'
        ]

so in views.py i want to filter books by authors

views.py
class BooksListAPIView(generics.ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = (filters.OrderingFilter, DjangoFilterBackend)
    filter_fields = ['published_date', 'authors']
    ordering_fields = ['published_date']

but it gives me this error

'Meta.fields' must not contain non-model field names: authors 

any idea how can i filter data with authors so i can extract books of given authors. I would like to have a choice of selecting filters. Thanks in advance.

Upvotes: 4

Views: 3802

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477543

You remove the authors from the fields, and let this be handled by the AuthorSerializer in the serializer:

class BookSerializer(serializers.ModelSerializer):
    authors = AuthorSerializer(source='author_set', many=True)

    class Meta:
        model = Book
        fields = [  # ← no authors
            'author_set',
            'title',
            'published_date',
            'categories',
            'average_rating',
            'ratings_count',
            'thumbnail'
        ]

Note that you can rename the relation in reverse with the related_name=… parameter:

class Author(models.Model):
    name  = models.CharField(max_length=200)
    books = models.ManyToManyField(Book, related_name='authors')

    def __str__(self):
        return self.name

in that case, the source is simply authors:

class BookSerializer(serializers.ModelSerializer):
    #                   no source ↓
    authors = AuthorSerializer(many=True)

    class Meta:
        model = Book
        fields = [
            'authors',
            'title',
            'published_date',
            'categories',
            'average_rating',
            'ratings_count',
            'thumbnail'
        ]

Upvotes: 3

Related Questions