AminA2
AminA2

Reputation: 197

Filter output items of reverse relations in Django

I have these models:

class Author(models.Model):
    name = models.CharField(max_length=50)


class Book(models.Model):
    name = models.CharField(max_length=150)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")
    published_at = models.DateField()

And this is my query:

Author.objects.filter(books__published_at__ragne=[date_from, date_to]).annotate(books_count=Count('books'))

The query's output will be sent to below serializer(inherit django rest framework serializer):

class AuthorSerializer(serializers.ModelSerializer):
    books_count= serializers.IntegerField(read_only=True)
    books = serializers.StringRelatedField(many=True)

    class Meta:
        model = Author
        fields = ['id', 'name', 'books_count', 'books']

The AuthorSerializer output will be all authors who have at least one book published in specified range, with the number of books published by each author, and also the string representation of all books of each author.

The books__published_at__ragne filter affect output authors and books count, but it won't affect books of authors. I mean for each author, all books are returned, not only books which are published in specified range.

How can i also filter books with that specified parameters?

Upvotes: 4

Views: 108

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476977

You can work with a Prefetch object:

from django.db.models import Prefetch

Author.objects.filter(
    books__published_at__range=[date_from, date_to]
).annotate(books_count=Count('books')).prefetch_related(
    Prefetch(
        'books',
        queryset=Book.objects.filter(published_at__ragne=[date_from, date_to])
    )
)

This thus means that books_count will determine the number of books published in that range, and the books list will also contain only these books.

Upvotes: 1

Related Questions