У меня в руках загадка. В качестве упражнения я пытаюсь написать набор запросов, который поможет мне визуализировать, с какими из моих профессиональных контактов я должен отдавать приоритет переписке.
Для этого у меня есть пара моделей:
class Person(models.Model):
name = models.CharField(max_length=256)
email = models.EmailField(blank=True, null=True)
target_contact_interval = models.IntegerField(default=45)
class ContactInstance(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='contacts')
date = models.DateField()
notes = models.TextField(blank=True, null=True)
Столбец target_contact_interval
на модели Person
обычно указывает максимальное количество дней, которое должно пройти, прежде чем я свяжусь с вами. снова этому человеку.
A ContactInstance
отражает единственную точку контакта с Person
. A Person
может иметь обратную связь со многими ContactInstance
объектами.
Итак, первый Person
в наборе запросов должен обладать наибольшей разницей между date
самых последних ContactInstance
связанных к нему и самому себе target_contact_interval
Итак, функция моей мечты будет выглядеть примерно так:
Person.objects.order_by(contact__latest__date__day - timedelta(days=F(target_contact_interval))
, но, конечно, это не сработает по разным причинам.
Я уверен, что кто-то мог бы написать для этого необработанные PostgreSQL, но мне действительно любопытно узнать, есть ли способ выполнить sh это, используя только Django ORM.
Вот фрагменты, которые я нашел до сих пор, но у меня возникли проблемы с их соединением.
Возможно, я смогу использовать Subquery
, чтобы отметить дату наиболее недавняя точка данных:
from django.db.models import OuterRef, Subquery
latest = ContactInstance.objects.filter(person=OuterRef('pk')).order_by('-date')
Person.objects.annotate(latest_contact_date=Subquery(latest.values('date')[:1]))
И мне нравится идея сортировки нулевых значений в конце :
from django.db.models import F
Person.objects.order_by(F('last_contacted').desc(nulls_last=True))
Но я не знаю, куда go отсюда. Я пытался поместить все в order_by()
, но не могу понять, можно ли использовать F()
с аннотированными значениями или с timedelta
в моем случае.
ОБНОВЛЕНИЕ: У меня есть изменил модель target_contact_interval
на DurationField
, как было предложено. Вот запрос, который я пытаюсь использовать:
ci = ContactInstance.objects.filter(
person=OuterRef('pk')
).order_by('-date')
Person.objects.annotate(
latest_contact_date=Subquery(ci.values('date'[:1])
).order_by((
(datetime.today().date() - F('latest_contact_date')) -
F('target_contact_interval')
).desc(nulls_last=True))
Мне кажется, что это должно сработать, однако набор запросов по-прежнему упорядочен неправильно.