如何在Django中按日期范围过滤查询对象?

问题:如何在Django中按日期范围过滤查询对象?

我在一个模型中有一个领域,例如:

class Sample(models.Model):
    date = fields.DateField(auto_now=False)

现在,我需要按日期范围过滤对象。

如何过滤日期在1-Jan-2011和之间的所有对象31-Jan-2011

I’ve got a field in one model like:

class Sample(models.Model):
    date = fields.DateField(auto_now=False)

Now, I need to filter the objects by a date range.

How do I filter all the objects that have a date between 1-Jan-2011 and 31-Jan-2011?


回答 0

Sample.objects.filter(date__range=["2011-01-01", "2011-01-31"])

或者,如果您只是想按月过滤:

Sample.objects.filter(date__year='2011', 
                      date__month='01')

编辑

正如伯恩哈德Vallant说,如果你想查询集去掉了specified range ends,你应该考虑自己的解决方案,它采用GT / LT(大于/小于号)。

Use

Sample.objects.filter(date__range=["2011-01-01", "2011-01-31"])

Or if you are just trying to filter month wise:

Sample.objects.filter(date__year='2011', 
                      date__month='01')

Edit

As Bernhard Vallant said, if you want a queryset which excludes the specified range ends you should consider his solution, which utilizes gt/lt (greater-than/less-than).


回答 1

您可以对对象使用djangofilterdatetime.date

import datetime
samples = Sample.objects.filter(sampledate__gte=datetime.date(2011, 1, 1),
                                sampledate__lte=datetime.date(2011, 1, 31))

You can use django’s filter with datetime.date objects:

import datetime
samples = Sample.objects.filter(sampledate__gte=datetime.date(2011, 1, 1),
                                sampledate__lte=datetime.date(2011, 1, 31))

回答 2

使用过滤器进行Django范围设置时,请确保您知道使用日期对象与日期时间对象之间的区别。__range是日期中包含的内容,但是如果您使用datetime对象作为结束日期,则如果未设置时间,它将不包括该天的条目。

    startdate = date.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

返回从开始日期到结束日期的所有条目,包括那些日期的条目。不好的例子,因为这将在未来一周返回条目,但您会遇到麻烦。

    startdate = datetime.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

根据日期字段的设置时间,将缺少24小时的输入值。

When doing django ranges with a filter make sure you know the difference between using a date object vs a datetime object. __range is inclusive on dates but if you use a datetime object for the end date it will not include the entries for that day if the time is not set.

    startdate = date.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

returns all entries from startdate to enddate including entries on those dates. Bad example since this is returning entries a week into the future, but you get the drift.

    startdate = datetime.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

will be missing 24 hours worth of entries depending on what the time for the date fields is set to.


回答 3

通过使用datetime.timedelta在范围中的最后一个日期添加日期,可以避免由于DateTimeField/date对象比较精度不足而导致的“阻抗不匹配”(如果使用范围,则可能发生)。其工作原理如下:

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])

如前所述,如果不这样做,记录将在最后一天被忽略。

进行编辑以避免使用datetime.combine-与a进行比较时,坚持日期实例似乎更合乎逻辑DateTimeField,而不是乱扔掉(且容易混淆)datetime对象。请参阅下面的注释中的进一步说明。

You can get around the “impedance mismatch” caused by the lack of precision in the DateTimeField/date object comparison — that can occur if using range — by using a datetime.timedelta to add a day to last date in the range. This works like:

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])

As discussed previously, without doing something like this, records are ignored on the last day.

Edited to avoid the use of datetime.combine — seems more logical to stick with date instances when comparing against a DateTimeField, instead of messing about with throwaway (and confusing) datetime objects. See further explanation in comments below.


回答 4

很简单

YourModel.objects.filter(YOUR_DATE_FIELD__date=timezone.now())

为我工作

Is simple,

YourModel.objects.filter(YOUR_DATE_FIELD__date=timezone.now())

Works for me


回答 5

为了使其更加灵活,可以设计如下的FilterBackend:

class AnalyticsFilterBackend(generic_filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        predicate = request.query_params # or request.data for POST

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is not None:
            queryset = queryset.filter(your_date__range=(predicate['from_date'], predicate['to_date']))

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is None:
            queryset = queryset.filter(your_date__gte=predicate['from_date'])

        if predicate.get('to_date', None) is not None and predicate.get('from_date', None) is None:
            queryset = queryset.filter(your_date__lte=predicate['to_date'])
        return queryset

To make it more flexible, you can design a FilterBackend as below:

class AnalyticsFilterBackend(generic_filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        predicate = request.query_params # or request.data for POST

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is not None:
            queryset = queryset.filter(your_date__range=(predicate['from_date'], predicate['to_date']))

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is None:
            queryset = queryset.filter(your_date__gte=predicate['from_date'])

        if predicate.get('to_date', None) is not None and predicate.get('from_date', None) is None:
            queryset = queryset.filter(your_date__lte=predicate['to_date'])
        return queryset

回答 6

今天仍然有意义。您也可以这样做:

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)

Still relevant today. You can also do:

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)