【问题标题】:How do I filter query objects by date range in Django?如何在 Django 中按日期范围过滤查询对象?
【发布时间】:2011-06-07 19:19:25
【问题描述】:

我在一个模型中有一个字段,例如:

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

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

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

【问题讨论】:

    标签: python django django-models django-queryset


    【解决方案1】:

    您可以使用“__range” 例如:

    from datetime import datetime
    start_date=datetime(2009, 12, 30)
    end_date=datetime(2020,12,30)
    Sample.objects.filter(date__range=[start_date,end_date])
    

    【讨论】:

    • 第三行的end_end应该是end_date
    • 感谢您的指正;以下错误已更正。
    【解决方案2】:

    在使用过滤器处理 django 范围时,请确保您知道使用日期对象和日期时间对象之间的区别。 __range 包含日期,但如果您使用 datetime 对象作为结束日期,如果未设置时间,它将不包括当天的条目。

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

    返回从 startdate 到 enddate 的所有条目,包括这些日期的条目。不好的例子,因为这是在未来一周内返回条目,但你明白了。

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

    将丢失 24 小时的条目,具体取决于日期字段设置的时间。

    【讨论】:

    • 我认为重要的是要注意如何导入date 对象:>>> from datetime import date >>> startdate = date.today()
    【解决方案3】:

    为了更灵活,你可以设计一个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
    

    【讨论】:

      【解决方案4】:

      很简单,

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

      适合我

      【讨论】:

      • 这对我也有用,对于新手来说,为了清楚起见:(date__date=...) 表示 ({whateverColumnTheDateIsCalled}__date)
      • OP 要求提供一个范围
      【解决方案5】:

      使用

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

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

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

      编辑

      正如 Bernhard Vallant 所说,如果您想要一个不包括 specified range ends 的查询集,您应该考虑使用 gt/lt(大于/小于)的 his solution

      【讨论】:

      • date1 的数据类型是什么?我现在有了 datetime 对象。
      • @dcordjer:另外应该说__range 包括边界(如sql 的BETWEEN),如果您不希望包括边界,则必须使用我的gt/lt 解决方案...
      • 这是否天生按任何顺序排序?如果是这样,哪个顺序?谢谢。
      • @RichardDunn 排序将基于您的模型的默认排序,或者如果您使用order_by 而不是上面提到的QuerySet 生成的QuerySet。我已经好几年没用过 Django了。
      • 对于 date__range,您需要输入下个月的 01。这是指向文档的链接,该链接将其转换为日期的 00:00:00.0000,因此不包括您范围内的最后一天。 docs.djangoproject.com/en/1.10/ref/models/querysets/#range 在这种情况下我使用: date__range=["%s-%s-1"%(year,month),"%s-%s-1"%(year,int(month)+1)]
      【解决方案6】:

      您可以将django's filterdatetime.date objects 一起使用:

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

      【讨论】:

        【解决方案7】:

        您可以通过使用 datetime 来解决由于 DateTimeField/date 对象比较中缺乏精确性而导致的“阻抗不匹配”——如果使用 range 可能会出现这种情况。 timedelta 将日期添加到范围内的最后一个日期。这就像:

        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 进行了编辑——在与DateTimeField 进行比较时,坚持使用日期实例似乎更合乎逻辑,而不是使用一次性(和令人困惑的)datetime 对象。请参阅下面的 cmets 中的进一步说明。

        【讨论】:

        • 有一个很棒的 Delorean 库,它通过截断方法简化了这一点:delorean.readthedocs.org/en/latest/quickstart.html#truncation
        • @tojjer:看起来很有希望,但是我们如何在这里使用 truncate 方法?
        • @eugene:我刚刚再次探讨了这个问题,经过几个月的时间,你说得对,毕竟在这种情况下它并没有真正的帮助。我能想到的唯一解决方法是在我的原始回复中建议,即在过滤日期实例时提供额外的“填充”以与日期时间模型字段进行比较。这可以通过上面的 datetime.combine 方法完成,但我发现通过将 timedelta(days=1) 添加到范围内的开始/结束日期来仅适应差异可能会更简单一些 - - 取决于问题。
        • 所以Example.objects.filter(created__range=[date(2014, 1, 1), date(2014, 2, 1)]) 不会包含在date(2014, 2, 1) 上创建的对象,正如@cademan 所解释的那样。但是,如果您通过添加一天来增加结束日期,您将获得一个查询集,涵盖那些丢失的对象(并且由于相同的怪癖而方便地省略在 date(2014, 2, 2) 上创建的对象)。这里令人讨厌的是用created__gte ... created__lte=date(2014, 2, 1) 指定的“手动”范围也不起作用,这绝对是违反直觉的恕我直言。
        • @tojjer: datetime_field__range = [delorean.parse('2014-01-01').date, delorean.parse('2014-02-01').date] 适合我
        猜你喜欢
        • 2022-07-07
        • 2014-09-04
        • 1970-01-01
        • 1970-01-01
        • 2020-03-05
        • 1970-01-01
        • 2019-03-10
        • 1970-01-01
        • 2011-05-25
        相关资源
        最近更新 更多