Запрос истек разница во времени в Django ORM


У меня есть простая модель для описания задачи и периода между ее выполнением:

class Task(models.Model):
    last_check_timestamp = models.DateTimeField(blank=True, null=True, db_index=True)

class TaskSchedule(models.Model):
    task = models.OneToOneField(Task, blank=False, null=False, related_name='schedule')
    interval_seconds = models.IntegerField(blank=False, null=False)

Я хочу иметь возможность запрашивать, используя ORM Джанго, какие задачи свежие, а какие устаревшие, то есть те, которые должны выполняться в соответствии с их расписанием.

В настоящее время я вычисляю это для конкретной записи без ORM через:

import datetime
task = Task.objects.get(id=123)
fresh = task.last_check_timestamp is not None and datetime.datetime.now() < (task.last_check_timestamp + datetime.timedelta(seconds=task.schedule.interval_seconds))

Как бы я сделал эквивалент с ORM Джанго, чтобы я мог запросить все свежие / устаревшие задачи сразу?

Например, это очевидно, не работает, но что-то вроде:

Tasks.objects.filter(Q(last_check_timestamp__isnull=True) || Q(last_check_timestamp + datetime.timedelta(seconds=schedule__interval_seconds)))
1 2

1 ответ:

Недавно мне пришлось сделать аналогичный запрос. Я надеялся сделать это с помощью F() объекты, но я не думаю, что это возможно, потому что timedelta полагается на столбец db (это было бы возможно, если бы schedule_interval_seconds был константой).

В конце концов, я сделал запрос, используя ORM с extra(), и написал SQL для предложения where.

sql = "DATE_ADD(last_check_timestamp, INTERVAL schedule.interval_seconds SECOND) < DATE(NOW())"
Tasks.objects.filter(Q(last_check_timestamp__isnull=True) || Q(last_check_timestamp + datetime.timedelta(seconds=schedule__interval_seconds)))
tasks = Task.object.select_related('schedule').extra(where=[sql,]

Здесь используется функция DATE_ADD (MySQL docs). Возможно, вам придется приспособиться к различным вкусам SQL. select_related требуется так что Джанго делает соединение с таблицей расписания.

Выше не выбираются задачи, где last_check_timestamp равно null. Я не думаю, что вы можете использовать combine extra() и ваш объект Q, но вы можете расширить инструкцию SQL.

sql = """last_check_timestamp is NULL or DATE_ADD(last_check_timestamp, INTERVAL schedule.interval_seconds SECOND) < DATE(NOW())"""