Подсчет общих членов ManyToMany в наборе запросов

Предположим, что у меня есть такие модели:

class Bar(models.Model):
    pass # some simple Model goes here

class Foo(models.Model):
    bars = models.ManyToManyField(Bar)

При наличии некоторой переменной main_object = Foo() с заполненными bars, как я могу сделать Queryset так, чтобы он был аннотирован количеством общих bars элементов между каждой сущностью и main_object?

Пример:

Имеется три записи Bar, с первичными ключами 1, 2 и 3. main_object имеет pk=2 как набор членов в bars.

Foo имеет две записи: main_object и еще одна с pk=1, установленным в bars. В этом случае мне нужна аннотация, имеющая значение 0, поскольку указанная запись не имеет общих внешних ключей Bar с main_object.

Я могу представить нечто подобное Foo.objects.filter(bars__in=<some_values_here>), но вместо простой проверки наличия, фактически подсчитывая его, как from django.db.models.Count.

Решаема ли она вообще с помощью Querysets или я должен прибегнуть к ручному подсчету через циклы?

В практическом использовании такой способ запроса может быть полезен при ранжировании по сходству, но мне он кажется нетривиальным.

Вы можете считать с:

from django.db.models import Count, Q

Foo.objects.annotate(
    common_count=Count(
        'bars',
        filter=Q(bars__foo=main_object)
    )
)

или если вы хотите получить только те объекты, которые имеют хотя бы одно общее Bar:

Foo.objects.filter(
    bars__foo=main_object
).distinct()
Вернуться на верх