Вы можете аннотировать пары, например:
from django.db.models import Count, F, Q
Person.objects.filter(
Q(pair__mates__lt=F('pk')) | Q(pair__mates__gt=F('pk'))
).values(
city1=F('city__name'),
city2=F('pair__mates__city__name')
).annotate(
<b>number=Count('pk')</b>
).order_by('city1', 'city2')
__name
должно быть полем города, который вы хотите использовать. Например, __pk
тоже может быть опцией.
Запрос работает следующим образом: Q(pair__mates__lt=F('pk')) | Q(pair__mates__gt=F('pk'))
обычно должен исключать «товарищей», которые относятся к тому же Person
. Затем мы используем .values(..)
, чтобы получить name
(или другое поле) из города и из pair__mates__city__names
. Теперь, когда у нас есть эти два значения, мы получаем Count(..)
количество записей в группе из city1
и city2
. .order_by(..)
необходим, чтобы избежать этого индексации, например, qs[1]
вернет одну запись из исходного запроса Person
.
Таким образом, запрос выглядит так:
SELECT app_name_city.name AS city1,
T5.name AS city2,
COUNT(app_name_person.id) AS number
FROM app_name_person
INNER JOIN app_name_pair ON app_name_person.pair_id = app_name_pair.id
INNER JOIN app_name_person T3 ON app_name_pair.id = T3.pair_id
INNER JOIN app_name_city ON app_name_person.city_id = app_name_city.id
INNER JOIN app_name_city T5 ON T3.city_id = T5.id
WHERE T3.id < app_name_person.id OR T3.id > app_name_person.id
GROUP BY app_name_city.name, T5.name
ORDER BY city1 ASC, city2 ASC
Это вернет QuerySet
словарей:
<QuerySet [
{'city1': 'city_a', 'city2': 'city_a', 'number': 80},
{'city1': 'city_a', 'city2': 'city_b', 'number': 100},
{'city1': 'city_b', 'city2': 'city_c', 'number': 200}
]>