Аннотирование Django QuerySet с подсчетом подзапроса
Я создаю доску объявлений о работе. Каждая Job может иметь несколько связанных с ней Location объектов.
Я разработал свои модели местоположения и работы следующим образом:
class Location(BaseModel):
    slug = models.CharField(unique=True)
    city = models.OneToOneField(to="City", null=True)
    state = models.ForeignKey(to="State", null=True)
    country = models.ForeignKey(to="Country")
class Job(BaseModel):
    title = models.CharField()
    description = models.TextField()
    locations = models.ManyToManyField(
        to="Location",
        related_name="jobs",
        through="JobLocation",
    )
Итак, объект Location имеет возможность ссылаться на наше представление о стране (например, United States), штате (например, New York) или городе (например, Manhattan). Я заполняю поле slug модели Location следующим образом:
- Если объект Location - страна, я использую название страны. - united-states
 
- Если объект Location является государством, я использую (название государства + название страны). - new-york-united-states
 
- Если объект Location - город, я использую (название города + название штата + название страны). - manhattan-new-york-united-states
 
 Заполнив таким образом поле slug, я могу упростить запрос всех вакансий в определенном месте с помощью поиска endswith. Например, если есть вакансия Python в Манхэттене, штат Нью-Йорк, и вакансия React в Бруклине, штат Нью-Йорк, я могу получить все вакансии в штате Нью-Йорк следующим образом:
Job.objects.filter(locations__slug__endswith="new-york-united-states").distinct()
 Теперь я хочу получить список всех моих объектов Location, и чтобы каждый элемент Location был аннотирован number_of_jobs. Это number_of_jobs должно быть количество всех рабочих мест в данном конкретном местоположении.
Например:
-  Объект местоположения Манхэттен должен иметь number_of_jobs=1(задание Python)
-  Объект локации Бруклин должен иметь number_of_jobs=1(Работа с React)
-  Объект локации Нью-Йорк должен иметь number_of_jobs=2(задание Python + задание React)
Попытка 1:
 Самое простое решение, заключающееся в том, чтобы Count подставить Location.jobs, не работает. Он показывает 1 задание для Манхэттена и 1 задание для Бруклина, но 0 заданий для Нью-Йорка.
Location.objects.annotate(number_of_jobs=Count("jobs", distinct=True))
# 1 job for Manhattan
# 1 job for Brooklyn
# 0 job for New York 
Попытка 2:
subquery = Job.objects.filter(locations__slug__endswith=OuterRef("slug")).distinct().count()
Location.objects.annotate(number_of_jobs=Subquery(subquery))
 Это также не работает, потому что count() выполняет набор запросов немедленно.
Попытка 3:
Основываясь на ответе Ювраджа, мне удалось приблизиться к ответу, но не совсем.
jobs = Job.objects.filter(locations__slug__endswith=OuterRef("slug"))
subquery = jobs.annotate(job_count=Count("id", distinct=True)).values("job_count")[:1]
Location.objects.annotate(number_of_jobs=Subquery(subquery))
 Если я запускаю эти выражения, используя debugsqlshell из django-debug-toolbar, и копирую SQL, который создает Django, и  удаляю предложение GROUP BY, я получаю 100% правильный ответ. Я пока не понимаю, зачем Django добавляет GROUP BY и почему его удаление дает правильный ответ.
Я нахожусь в затруднительном положении с этим набором вопросов. Буду благодарен за любую помощь.
 Есть более эффективный способ решения этой задачи. Вы можете обработать агрегацию с помощью Subquery без прямого вызова .count(), который, как вы заметили, оценивает набор запросов раньше времени. Вместо этого следует использовать annotate() и условный Count для связанных экземпляров Job.
from django.db.models import Count, OuterRef, Subquery, F
# Subquery to count the jobs related to a location slug usingendswithlookup
subquery = Job.objects.filter(
locations__slug__endswith=OuterRef('slug')).values('id')
# Annotating the location objects with the count of jobs
locations_with_job_count = Location.objects.annotate(
number_of_jobs=Subquery(
    Job.objects.filter(locations__slug__endswith=OuterRef('slug'))
    .annotate(job_count=Count('id'))
    .values('job_count')[:1]
))
Прежде всего, спасибо Ювраджу за ваш ответ. Этот ответ основывается на вашем.
 Оказывается, Django автоматически добавляет предложение GROUP BY, когда вы используете агрегатную функцию Count. Я не совсем понимаю, зачем он добавляет предложение GROUP BY и почему его удаление дает правильные результаты в моем случае, поэтому не буду рассуждать. Но вот ответ, также основанный на комментарии  Сергея к этому ответу:
class NonAggregateCount(Count):
    # Gets rid of Django's automatic GROUP BY clause
    contains_aggregate = False
jobs = Job.objects.filter(locations__slug__endswith=OuterRef("slug"))
subquery = jobs.annotate(job_count=NonAggregateCount("id", distinct=True)).values("job_count")
Location.objects.annotate(number_of_jobs=Subquery(subquery))