Давайте представим, что у нас есть модель Event:
class Event(models.Model):
actor = models.ForeignKey(Actor, null=False, blank=False, on_delete=models.PROTECT)
happened_datetime = models.DateTimeField(_('When did the event took place?'), blank=False, null=False)
и актерская модель:
class Actor(models.Model):
name = models.CharField(_('Name'), max_length=100, blank=False, null=False, default='')
Через некоторое время у нас есть потенциально длинный список событий.
Как нам получить актеров, последние два события которых разделены на меньшее или большее, чем указанная временная дельта, например:
Дайте мне всех актеров, чьи последние и последующие события не разделены более чем на 10 дней
или
Дайте мне всех актеров, чьи последние и последующие события не разделены менее чем на 5 часов
Это Subquery
путь? ExpressionWrapper
с F
выражениями?
Примечание: приведенные выше запросы означают, что мы должны также фильтровать по тем, кто вызвал как минимум два события, с чем-то похожим на это:
actors_with_at_least_two = Actor.objects.annotate(
nb_events=Subquery(
Event.objects.filter(
actor=OuterRef('pk')
).values(
'actor__pk'
).order_by().annotate(
cnt=Count('*')
).values('cnt')[:1],
output_field=models.IntegerField()
)
).filter(
nb_events__gte=2
)
Вышеописанное работает хорошо, но я борюсь с фильтрацией с помощью "самоанализа" на той же таблице (timedelta и т. Д.). Любые идеи / подсказки будут любезно оценены! : -)
Я пробовал со следующим:
events = Event.objects.annotate(
delta_with_previous=Subquery(
Event.objects.filter(
actor=OuterRef('actor__pk')
).exclude(
pk=OuterRef('pk')
).latest(
'happened_datetime'
).values(
'actor__pk'
).order_by().values(
'happened_datetime'
)[:1],
output_field=models.DurationField
)
).filter(
delta_with_previous__lte=timedelta(days=2)
).order_by(
'actor__pk'
)
Но, похоже, он работает недостаточно хорошо.