1

In this question, we were given a solution to sort a query based on the intersection of two many to many fields. While it's a great answer, the restriction is that you have to filter first.

Say I have the same two models. Is there a way to annotate all results by count of intersection, so that I can display all Questions regardless of location, but still sorted by location?

class Location(models.Model):
    name = models.CharField(max_length=100)


class Profile(models.Model):
    locations_of_interest = models.ManyToManyField(Location)


class Question(models.Model):
    locations = models.ManyToManyField(Location)

I wish I could do something like this:

from django.db.models import Count

matching_profiles = Profile.objects.all().annotate(
    locnom=Count('locations_of_interest__in=question.locations.all()')
)

Any ideas? Do I just have to make two queries and merge them?

dster77
  • 196
  • 1
  • 12

2 Answers2

3

We can move the filtering in the Count function as well:

Profile.objects.annotate(
    locnom=Count('id', filter=Q(locations_of_interest__in=question.locations.all()))
)

The two are not equivalent in the sense that Profiles with no related Locations, or in case the question has no location, will still be included, in that case the .locnom of that Profile will be 0.

The query looks approximately like:

SELECT profile.*,
       COUNT(CASE WHEN proloc.location_id IN (1, 4, 5) THEN profile.id ELSE NULL)
           AS locnom
FROM profile
LEFT OUTER JOIN profile_locations_of_interest AS proloc
             ON profile.id = proloc.profile_id
GROUP BY profile.id

Where [1, 4, 5] are here sample ids of the related Locations of the question.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
0

try to use subquery https://docs.djangoproject.com/fr/2.0/ref/models/expressions/#subquery-expressions

Like this example: https://books.agiliq.com/projects/django-orm-cookbook/en/latest/subquery.html

from django.db.models import Subquery
users = User.objects.all()
UserParent.objects.filter(user_id__in=Subquery(users.values('id')))