使用数据库时钟的相对时间的 Django 查询

Django query with relative time using database's clock

我正在尝试查找最近 30 秒内更新的所有 ORM 对象。执行此操作的标准方法是:

    reftime = timezone.now() - relativedelta(seconds=30)
    queryset = MyModel.objects.filter(updated_at__gte=reftime)

只要所有应用程序服务器 运行 Django 应用程序的时钟都同步,这就可以工作,这听起来很容易,但实际上并非如此。时钟偏差是真实的。

幸运的是,数据库服务器只有一个时钟,我们应该可以将其作为此类事情的最终时钟。 django 在 django.db.models.functions 中有一个名为 Now() 的漂亮对象,它似乎对此类事情应该有所帮助。但我从来没有见过这种方法的任何代码示例,它通过任何数学运算将时间移动大约 30 秒。例如这不起作用:

    reftime = django.db.models.functions.Now() - relativedelta(seconds=30)

如何使用相对于 SQL 服务器时钟的时间戳进行 django ORM 查询?

您不应使用 relativedelta,而应使用 timedelta [Python-doc],因此:

from datetime import timedelta
from django.db.models.functions import Now

queryset = MyModel.objects.filter(<strong>updated_at__gte=Now()-timedelta(seconds=30)</strong>)

Django 已经实现了从 Now class 中减去 timedelta 的逻辑,因此为此创建了一个 SQL 表达式。 不是 relativedelta 的情况。

事实上,我们可以显示 Django 使用的查询:

>>> print(Event.objects.filter(updated_at__gte=Now()-relativedelta(seconds=30)).query)
SELECT `app_name_mymodel`.`id`, `app_name_mymodel`.`updated_at` FROM `app_name_mymodel` WHERE `app_name_mymodel`.`updated_at` >= (CURRENT_TIMESTAMP - relativedelta(seconds=+30))
>>> print(Event.objects.filter(updated_at__gte=Now()-timedelta(seconds=30)).query)
SELECT `app_name_mymodel`.`id`, `app_name_mymodel`.`updated_at` FROM `app_name_mymodel` WHERE `app_name_mymodel`.`updated_at` >= (CURRENT_TIMESTAMP - INTERVAL 30000000 MICROSECOND)

对于relativedelta它只是使用对象的str(…),而对于timedelta对象,它“理解”这种类型,并将其转换为相应的SQL方言等值。