Django How to Filter Model Instances and also Related Objects for Each Instance. Nested Filtering?

Viewed 363

I have three models, Genre, Movie and Review. Each genre can have multiple movies, and each movie can have multiple reviews. I have been trying to filter the related objects of a Genre instance such that the queryset contains only active movies, and each of those active movies contains only active reviews.

models.py

class Genre(models.Model):
    name = models.CharField(max_length=160)


class Movie(models.Model):
    genre = models.ForeignKey(Genre, null=True, on_delete=models.CASCADE, related_name='movies')
    title = models.CharField(max_length=160)
    active = models.BooleanField(default=True)


class Review(models.Model):
    movie = models.ForeignKey(Movie, null=True, on_delete=models.CASCADE, related_name='reviews')
    author = models.CharField(max_length=150)
    active = models.BooleanField(default=True)

How can I obtain a queryset from a Genre instance which contains only active movies and reviews? Thank you for your time!

edit: My goal is to use this queryset to retrieve each active movie, and then for each active movie, retrieve each active review. So, I am looking for a solution that gives a queryset which can easily be iterated in the order of active movies first, and then active reviews.

1 Answers

You can .filter(…) [Django-doc] with:

Review.objects.filter(active=True, movie__active=True, movie__genre=genre1)

One can use double underscores (__) to look "through" relations.

If you want to retrieve Movies and only the active reviews, we can work with a Prefetch object:

from django.db.models import Prefetch

Movie.objects.filter(active=True, genre=genre1).prefetch_related(
    Prefetch(
        'reviews',
        queryset=Review.objects.filter(active=True),
        to_attr='active_reviews'
    )
)

the Movies that arise from this queryset will have an attribute .active_reviews that contains only reviews that are active.

Related