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 и вместо этого применяет простой, более эффективный фильтр. Надеюсь, это поможет. Дайте мне знать, если это не совсем то, что вам нужно.