【问题标题】:Dynamic range filter based on field in DjangoDjango中基于字段的动态范围过滤器
【发布时间】:2014-11-27 06:18:47
【问题描述】:

我对 Django 比较陌生,还不熟悉 Django 查询集。 我想根据字段按日期时间范围过滤查询集。 在 MySQL 中我会这样做

WHERE (start_time < NOW() - INTERVAL duration MINUTE)

这里的 start_time 是一个日期时间,而 duration 是一个整数,表示持续时间,以分钟为单位。

如何在 Django 中以可移植的方式执行此操作?我知道我总是可以使用extra,但我更希望它同时在 MySQL 和 Sqlite3 中工作。这些数据库管理器似乎不共享任何日期时间函数。

【问题讨论】:

标签: django datetime django-queryset


【解决方案1】:

您可以在查询中使用“F”表达式来引用过滤器表达式中模型的字段(请参阅https://docs.djangoproject.com/en/dev/topics/db/queries/#using-f-expressions-in-filters

这意味着在过滤器中,对于任何特定行,可以说“time_atime_b 之前的位置”:

filter(time_a__lt=F('time_b')

但是,出现问题的原因是,根据this related questiontimedelta 不会接受动态F() 表达式......因此看起来需要自定义 SQL。但是,您可以在 Django 中在 sqlite 和 mysql 上自动测试它,以断言它在两者上都有效。

同时,一个避免自定义 SQL 的特别脏的解决方案是将 start_time 转换为 Unix 时间,这使得数学变得容易。

from calendar import timegm
from datetime import timedelta

from django.db import models
from django.db.models import F
from django.utils.timezone import now


class Journey(models.Model):
    name = models.CharField(max_length=64)
    start_time = models.IntegerField()
    duration_minutes = models.IntegerField()


def current_journeys():
    unow = timegm(now().utctimetuple())
    q = Journey.objects.filter(start_time__gt=unow-60*F('duration_minutes'))
    return q.all()

【讨论】:

  • 刚刚使用django.test.TestCase 进行了测试,它适用于 sqlite3 和 mysql 引擎。
  • 在我的情况下,它不是一个固定的范围。这取决于数据库中每一行的持续时间字段。这就是我明确说明 start_time 和 duration 类型的原因。
  • 我可能必须以一种完全避免该问题的方式来解决我的问题,但很高兴知道这是否可行。
  • 在我看来,如果您在每一行都有start_timeduration,您可以轻松计算出end_time 并将其存储在模型中 - 那么您就有了一个非常简单的字段过滤器将在不同的引擎之间兼容。我不清楚duration 来自每个实例内部,而不是外部提供。
  • @Sten-Åke 我现在更好地理解了您的问题,并链接到了相关问题,并用解决方案更新了我的答案。
猜你喜欢
  • 2020-12-26
  • 2022-08-14
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 2022-10-05
相关资源
最近更新 更多