Django ORM:过滤日期时间字段的时间增量
Django ORM: Filter on timedelta of Datetime fields
我正在尝试根据两个 DateTimeField
的时差获取帖子,例如,在发布后不到 10 分钟内被删除的帖子。
class Post(models.Model):
...
time_posted = models.DateTimeField()
time_deleted = models.DateTimeField(blank=True, null=True)
有了上面的模型,我试了一下;
from datetime import timedelta
Post.objects.exclude(deleted__isnull=True).annotate(
delta=F('time_deleted') - F('time_posted')
).filter(delta__lt=timedelta(minutes=10))
并获得了 TypeError: expected string or buffer
。然后我认为这可能是类型的变化(DateTime 对象产生 Time 对象)所以我尝试了 ExpressionWrapper
:
Post.objects.exclude(deleted__isnull=True).annotate(
delta=models.ExpressionWrapper(
F('time_deleted') - F('time_posted'),
output_field=models.TimeField())
).filter(delta__gt=timedelta(minutes=10))
但这也导致了同样的异常。
非常感谢任何帮助。
编辑
根据@ivan的建议,我尝试了DurationField()
。我不再得到异常,但增量总是 0
.
>>> post = Post.objects.exclude(deleted__isnull=True).annotate(
delta=ExpressionWrapper(F('deleted') - F('time'),
output_field=DurationField())
).first()
>>> post.time_posted
datetime.datetime(2015, 8, 24, 13, 26, 50, 857326, tzinfo=<UTC>)
>>> post.time_deleted
datetime.datetime(2015, 8, 24, 13, 27, 30, 521569, tzinfo=<UTC>)
>>> post.delta
datetime.timedelta(0)
output_field
kwarg 应该是 DurationField
,因为它在 Django 中存储 datetime.timedelta
,而 TimeField
存储 datetime.time
.
不过有一个警告:
Arithmetic with DurationField works in most cases. However on all databases other than PostgreSQL, comparing the value of a DurationField to arithmetic on DateTimeField instances will not work as expected.
在 SQLite 后端 DurationField
由存储微秒的 bigint
表示:
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'sqlite'
# ...
data_types = {
# ...
'DecimalField': 'decimal',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
# ...
}
因此,因为您使用的是 SQLite,所以您实际上需要 delta
以微秒为单位的值。请参阅 了解执行此操作的 Func
。
我正在尝试根据两个 DateTimeField
的时差获取帖子,例如,在发布后不到 10 分钟内被删除的帖子。
class Post(models.Model):
...
time_posted = models.DateTimeField()
time_deleted = models.DateTimeField(blank=True, null=True)
有了上面的模型,我试了一下;
from datetime import timedelta
Post.objects.exclude(deleted__isnull=True).annotate(
delta=F('time_deleted') - F('time_posted')
).filter(delta__lt=timedelta(minutes=10))
并获得了 TypeError: expected string or buffer
。然后我认为这可能是类型的变化(DateTime 对象产生 Time 对象)所以我尝试了 ExpressionWrapper
:
Post.objects.exclude(deleted__isnull=True).annotate(
delta=models.ExpressionWrapper(
F('time_deleted') - F('time_posted'),
output_field=models.TimeField())
).filter(delta__gt=timedelta(minutes=10))
但这也导致了同样的异常。
非常感谢任何帮助。
编辑
根据@ivan的建议,我尝试了DurationField()
。我不再得到异常,但增量总是 0
.
>>> post = Post.objects.exclude(deleted__isnull=True).annotate(
delta=ExpressionWrapper(F('deleted') - F('time'),
output_field=DurationField())
).first()
>>> post.time_posted
datetime.datetime(2015, 8, 24, 13, 26, 50, 857326, tzinfo=<UTC>)
>>> post.time_deleted
datetime.datetime(2015, 8, 24, 13, 27, 30, 521569, tzinfo=<UTC>)
>>> post.delta
datetime.timedelta(0)
output_field
kwarg 应该是 DurationField
,因为它在 Django 中存储 datetime.timedelta
,而 TimeField
存储 datetime.time
.
不过有一个警告:
Arithmetic with DurationField works in most cases. However on all databases other than PostgreSQL, comparing the value of a DurationField to arithmetic on DateTimeField instances will not work as expected.
在 SQLite 后端 DurationField
由存储微秒的 bigint
表示:
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'sqlite'
# ...
data_types = {
# ...
'DecimalField': 'decimal',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
# ...
}
因此,因为您使用的是 SQLite,所以您实际上需要 delta
以微秒为单位的值。请参阅 Func
。