问题
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?
回答1:
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 Profile
s with no related Location
s, 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 id
s of the related Location
s of the question
.
回答2:
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')))
来源:https://stackoverflow.com/questions/51504634/django-intersect-count-annotate-for-sorting