I'd like to filter objects on a ManyToManyField using two attributes of the objects that is pointed to by ManyToManyFeild. See the model below, this is a classical user-items relationship
from django.db import models
class Person(models.Model):
#    user = models.OneToOneField(User)
    name = models.CharField(max_length=50, blank=False, null=False, default=None, unique=True)
    ratings = models.ManyToManyField('Rating',
        related_name="persons"
    )
class Movie(models.Model):
    title = models.CharField(max_length=50, blank=False, null=False, default=None, unique=True)
    def __str__(self):
        return f"{self.title}"
class Rating(models.Model):
    movie = models.ForeignKey(Movie, models.CASCADE)
    value = models.SmallIntegerField(blank=False, null=False, default=None)
    def __str__(self):
        return f"{self.movie}:{self.value}"
So, I'd like to find all users who gave above certain rating to Movie1 AND above certain rating to Movie2.
I can do this with cascading filters:
>>> Person.objects\
 .filter(ratings__movie__title='Movie1', ratings__value__gte=5)\
 .filter(ratings__movie__title='Movie2', ratings__value__gte=1)\
 .all()
[[A<QuerySet [<Person: Person object (1)>]>
But I am looking for a way to filter on any arbitrary number of ratings, not just 2.
I have tried with Q (in the case single filter() for all cases), but the following doesn't work:
>>> Person.objects.filter(
  Q(ratings__movie__title='Movie1') & Q(ratings__value__gte=5),\
  Q(ratings__movie__title='Movie2') & Q(ratings__value__gte=1)
).all()
<QuerySet []>
Update:
I figured out, that since filters are lazy, I could cascade a required number of them them in a loop and then call .all() in the end, like this:
my_filters = [("Movie1", 2), ("Movie2", 3)]
f = Person.objects
for m,r in my_filters:
  f = f.filter(ratings__movie__title=m, ratings__value__gte=r)
selected_persons = f.all()
The question of course remains, how efficient is that query... So the question remains on how to do this with the best efficiency.
Thanks for help!
 
    