如何在Django中过滤DateTimeField的日期?


173

我试图过滤DateTimeField与日期比较。我的意思是:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

我得到一个空的查询集列表作为答案,因为(我认为)我不在考虑时间,但我希望“任何时间”。

Django中有一种简单的方法吗?

我在datetime中设置了时间,但不是00:00


5
这是Django的烦恼之一。考虑到这是一个简单且常见的用例,没有简单的方法可以实现。
rubayeet 2010年

Answers:


114

此类查询的实现django.views.generic.date_based方式如下:

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

因为它很冗长,所以有计划使用__date运算符来改进语法。有关更多详细信息,请检查“ #9596将DateTimeField与日期比较太难 ”。


4
在范围内使用: Q(created__gte=datetime.combine(created_value, time.min))
Dingo 2012年

10
看起来将在Django 1.9降落:github.com/django/django/commit/...
amjoconn

14
Django 1.9的新功能:Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))

102
YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

//在评论后编辑

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

不起作用,因为它创建了一个时间值设置为0的datetime对象,因此数据库中的时间不匹配。


谢谢答案!第一种选择不适用于datetimefields。第二个替代作品;)。如果有人知道另一种方法,请回答
Xidobix

使用datetime模块hrs,mins,secs中的使用datetime()的docs.python.org/library/datetime.html#datetime-objects是可选的。第二个是替换了vars的工作项目,您可以在文档中查看它的正确性
zalew

我知道它是可选的,问题是我的datetimefield已设置时间,它不是00:00
Xidobix

“第一种选择不适用于datetimefields。” 这非常令人惊讶,因为datetime.datetime()返回一个datetime对象djangoproject.com/documentation/0.96/models/basic检查模型定义和示例:pub_date = models.DateTimeField()pub_date = datetime(2005,7, 30)
zalew

“我知道这是可选的,问题是我的datetimefield设置了时间,而不是00:00”哦,现在我明白了。是的,没有时间参数,它设置为00,所以它不会返回:)
zalew

88

这是我使用ipython的timeit函数得到的结果:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

包含似乎更快。


该解决方案似乎是最新的。我很惊讶它获得了4次投票,因为当我尝试contains解决方案时,我收到了错误消息:Unable to get repr for <class 'django.db.models.query.QuerySet'>
Houman 2013年

我今天重新检查并更新了结果,但我认为您的错误不是由__contains过滤器引起的。但是,如果你遇到了问题,你应该尝试Django文档例如其使用__gte
莫雷诺

4
__contains方法对我来说很好用。我认为这可能是最好的答案,因为它提供了性能比较。我投了不止一票,但我感到惊讶的是它没有更多的投票。
RobotHumans

我喜欢startswith解决方案
。–

46

现在,Django具有__date queryset过滤器,可以针对开发版本中的日期查询datetime对象。因此,它将很快在1.9中可用。



最佳答案,适用于更新的Django版本
serfer2'3

这对我不起作用,不知道为什么:(我在django 1.11上,我的确切例外是:NotImplementedError:basedatabaseoperations的子类可能需要datetime_cast_date()方法
AbdurRehman Khan,

44
Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

以上是我用过的。它不仅有效,而且还具有一些固有的逻辑支持。


3
比这里的所有其他答案要好得多,谢谢!
2014年

sssss-shazam!💯–
dps

30

从Django 1.9开始,执行此操作的方法是__date在datetime对象上使用。

例如: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


27

这产生与使用__year,__ month和__day相同的结果,并且似乎对我有用:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

19
看起来像这样将日期对象转换为字符串,然后对日期进行字符串比较,因此强制db执行全表扫描。一张大桌子,这会影响您的表现
yilmazhuseyin 2011年

8

假设active_on是一个日期对象,将其增加1天,然后进行范围调整

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

2

这是一种有趣的技术-我利用在Django上在MySQL上实现的startswith过程来实现只在日期中查找日期时间的结果。基本上,当Django在数据库中进行查找时,它必须对DATETIME MySQL存储对象进行字符串转换,因此您可以对此进行过滤,而忽略日期的时间戳部分-这样%LIKE%仅与日期匹配对象,您将获得给定日期的每个时间戳。

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

这将执行以下查询:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

在这种情况下,无论时间戳如何,LIKE BINARY都将匹配日期中的所有内容。包括以下值:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

希望这对所有人都有帮助,直到Django提出解决方案为止!


好的,因此,这的答案似乎与上面的mhost和kettlehell相同,但是更多地描述了后端发生的情况。至少您有理由使用contains或startswith以及datetime的date()属性!
bbengfort 2012年

2

这里有一篇很棒的博客文章:在Django ORM中比较日期和日期时间

为Django> 1.7,<1.9发布的最佳解决方案是注册一个转换:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

然后可以在过滤器中使用它,如下所示:

Foo.objects.filter(created_on__date=date)

编辑

此解决方案绝对取决于后端。从文章:

当然,此实现依赖于具有DATE()函数的SQL的特定风格。MySQL确实如此。SQLite也是如此。另一方面,我还没有亲自使用PostgreSQL,但是通过谷歌搜索使我相信它没有DATE()函数。因此,这种简单的实现似乎必然与后端有关。


这是MySQL特有的吗?想知道类名的选择。
Binoj David

@BinojDavid是的,这取决于后端
Dan Gayle

我使用Django 1.8和PostgreSQL 9.6.6对其进行了测试,并且效果很好。实际使用PostgreSQL时,您还可以使用以下语法:return '{}::date'.format(lhs), params
michal-michalak,

1

嗯..我的解决方案正在工作:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))


0

在Django 1.7.6中工作:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

2
这仅在您要查找确切日期的情况下有效,__lte例如,您不能使用。
吉瓦尔

-1

请参阅文章Django文档

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

5
在django文档中它起作用,因为datetimefiled的时间为00:00
Xidobix
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.