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

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

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

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

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

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

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

I am trying to filter a DateTimeField comparing with a date. I mean:

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

I get an empty queryset list as an answer because (I think) I am not considering time, but I want “any time”.

Is there an easy way in Django for doing this?

I have the time in the datetime setted, it is not 00:00.


回答 0

此类查询的实现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与日期比较太难 ”。

Such lookups are implemented in django.views.generic.date_based as follows:

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

Because it is quite verbose there are plans to improve the syntax using __date operator. Check “#9596 Comparing a DateTimeField to a date is too hard” for more details.


回答 1

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对象,因此数据库中的时间不匹配。

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

// edit after comments

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

doest not work because it creates a datetime object with time values set to 0, so the time in database doesn’t match.


回答 2

这是我使用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

包含似乎更快。

Here are the results I got with ipython’s timeit function:

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

contains seems to be faster.


回答 3

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

Now Django has __date queryset filter to query datetime objects against dates in development version. Thus, it will be available in 1.9 soon.


回答 4

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

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

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

the above is what I’ve used. Not only does it work, it also has some inherent logical backing.


回答 5

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

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

As of Django 1.9, the way to do this is by using __date on a datetime object.

For example: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


回答 6

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

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

This produces the same results as using __year, __month, and __day and seems to work for me:

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

回答 7

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

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

assuming active_on is a date object, increment it by 1 day then do range

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

回答 8

这是一种有趣的技术-我利用在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提出解决方案为止!

Here is an interesting technique– I leveraged the startswith procedure as implemented with Django on MySQL to achieve the result of only looking up a datetime through only the date. Basically, when Django does the lookup in the database it has to do a string conversion for the DATETIME MySQL storage object, so you can filter on that, leaving out the timestamp portion of the date– that way %LIKE% matches only the date object and you’ll get every timestamp for the given date.

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

This will perform the following query:

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

The LIKE BINARY in this case will match everything for the date, no matter the timestamp. Including values like:

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

Hopefully this helps everyone until Django comes out with a solution!


回答 9

这里有一篇很棒的博客文章:在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()函数。因此,这种简单的实现似乎必然与后端有关。

There’s a fantastic blogpost that covers this here: Comparing Dates and Datetimes in the Django ORM

The best solution posted for Django>1.7,<1.9 is to register a transform:

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()

Then you can use it in your filters like this:

Foo.objects.filter(created_on__date=date)

EDIT

This solution is definitely back end dependent. From the article:

Of course, this implementation relies on your particular flavor of SQL having a DATE() function. MySQL does. So does SQLite. On the other hand, I haven’t worked with PostgreSQL personally, but some googling leads me to believe that it does not have a DATE() function. So an implementation this simple seems like it will necessarily be somewhat backend-dependent.


回答 10

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

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

Hm.. My solution is working:

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

回答 11

Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)

回答 12

在Django 1.7.6中工作:

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

In Django 1.7.6 works:

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

回答 13

请参阅文章Django文档

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

See the article Django Documentation

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