Можно упаковать все в одну строку:
Project.objects.filter(tags__in=current_project.tags.all()).annotate(Count('name')).order_by('-name__count')[:3]
Или, разбито на шаги:
tags = current_project.tags.all()
matches = Project.objects.filter(tags__in=tags).annotate(Count('name'))
results = matches.order_by('-name__count')[:3]
Логика выглядит следующим образом:
current_project
- это экземпляр проекта, для которого вы хотите установить отношения.
-
filter
выбирает все проекты, теги которых совпадают с текущим проектом.
-
annotate
добавляет переменную к возвращаемым значениям, которая подсчитывает количество похожих имен. Поскольку проекты, соответствующие нескольким тегам, возвращаются несколько раз, это значение указывает на количество совпадений.
- Результаты отсортированы по аннотированной переменной
name__count
. Чтобы получить первые 3 результата, список ограничен с помощью [:3]
.