Django аннотация + фильтрация

У меня есть некоторые данные, которые я загрузил из SQLite в PSQL с помощью pgloader, это работает более или менее, но некоторые типы немного неуклюжи, поэтому мои даты в строке, но я не думаю, что это проблема (могу ошибаться)

Рассмотрите следующие модели:

class User(models.Model):
    hash_id = models.TextField(primary_key=True)
    first_name = models.TextField(blank=True, null=True)
    last_name = models.TextField(blank=True, null=True)
class Education(models.Model):
    hash_code = models.ForeignKey('Users', models.CASCADE)
    startdate = models.TextField(blank=True, null=True)
    enddate = models.TextField(blank=True, null=True)
class Job(models.Model):
    hash_code = models.ForeignKey('Users', models.CASCADE)
    jobends = models.TextField(blank=True, null=True)
    jobstarts = models.TextField(blank=True, null=True)

Я пытаюсь получить все вакансии через X лет после первого образования пользователя. На данный момент у меня есть подзапрос, чтобы получить дату начала первого образования для каждого пользователя:

# This should return a date eg: '2000-01-01'
mba_start_subq = Educations.objects.filter(hash_code=OuterRef('hash_code'))
        .order_by('startdate')
        .values('startdate')[:1]
    )

Затем я добавляю это к каждому заданию через:

jobs = (Job.objects.all()
        # .distinct('hash_code')
        .order_by('hash_code')
        .annotate(mba_start = Subquery(mba_start_subq))
       )

Пока все хорошо, проблема в том, что когда я пытаюсь добавить .filter() после этого, требуется много времени, чтобы получить ответ (в основном бесконечный цикл)

       # Filtering with date strings works
        jobs.filter(
            Q(jobstarts__lt = '2000-01-01'),
            Q(jobends__gt = '2002-01-01')
        )

       # this is the desired functionality, that doesn't work
        jobs.filter(
            Q(jobstarts__lt = Subquery(mba_start_subq)),
            Q(jobends__gt = Subquery(mba_start_subq))
        )

Я также пытался использовать F(annotated_value) в .filter() после того, как я аннотировал его в queryset, но не повезло, я не получаю никакого ответа от сервера вообще, это занимает целую вечность.

Что я пропустил? Способ, которым я получаю дату начала обучения, неправильный? Есть ли более эффективный способ?

Чтобы соответствовать SQL-запросу, который у вас есть, я бы использовал следующее:

subq = Education.objects.filter(hash_code__id=OuterRef('hash_code__id'))
                        .order_by('startdate')

Для фильтрации используется ID объекта User, а не весь объект. Значения также могут быть добавлены как часть подзапроса после. Окончательный запрос к заданиям можно выполнить следующим образом:

jobs = Job.objects.filter(jobstarts__lt=Subquery(subq.values('startdate')[:1]),
                          jobends__gt=Subquery(subq.values('startdate'[:1]))
                  .order_by('hash_code__id')

Это устраняет необходимость упорядочивать и аннотировать все объекты Jobs и вместо этого применяет простой, более эффективный фильтр. Надеюсь, это поможет. Дайте мне знать, если это не совсем то, что вам нужно.

Вернуться на верх