【问题标题】:Django filter events occurring today今天发生的 Django 过滤器事件
【发布时间】:2012-06-30 00:32:51
【问题描述】:

我正在努力在 Django 过滤器中逻辑地表示以下内容。我有一个“事件”模型和一个位置模型,可以表示为:

class Location(models.Model):
    name = models.CharField(max_length=255)

class Event(models.Model):
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()
    location = models.ForeignKeyField(Location)

    objects = EventManager()

对于给定的位置,我想选择今天发生的所有事件。我已经通过 EventManager 中的 'bookings_today' 方法尝试了各种策略,但正确的过滤器语法让我望而却步:

class EventManager(models.Manager):
    def bookings_today(self, location_id):
        bookings = self.filter(location=location_id, start=?, end=?)

date() 失败,因为这会将时间归零,并且白天的时间对应用程序至关重要,日期的最小值和最大值也是如此,并将它们用作书挡。此外,还有多种可能的有效配置:

start_date < today, end_date during today
start_date during today, end_date during today
start_date during today, end_date after today

我需要编写一整套不同的选项还是有更简单优雅的方法?

【问题讨论】:

标签: python django


【解决方案1】:

您需要两个不同的 datetime 阈值 - today_starttoday_end

from datetime import datetime, timedelta, time

today = datetime.now().date()
tomorrow = today + timedelta(1)
today_start = datetime.combine(today, time())
today_end = datetime.combine(tomorrow, time())

今天发生的任何事情都必须在之前 today_end 结束之后 today_start,所以:

class EventManager(models.Manager):
    def bookings_today(self, location_id):
        # Construction of today_end / today_start as above, omitted for brevity
        return self.filter(location=location_id, start__lte=today_end, end__gte=today_start)

(附注:有一个名为 foo_dateDateTimeField(不是 DateField)具有令人恼火的误导性 - 只需考虑 startend...)

【讨论】:

  • datetime.now()
  • datetime.now() 产生 AtrributeError
  • 对于未来的读者,请考虑anthony-anyanwu的回答,因为它是时区感知的。
【解决方案2】:

我看到的答案都不支持时区。

你为什么不这样做呢:

from django.utils import timezone

class EventManager(models.Manager):
    def bookings_today(self, location_id):
        bookings = self.filter(location=location_id, start__gte=timezone.now().replace(hour=0, minute=0, second=0), end__lte=timezone.now().replace(hour=23, minute=59, second=59))

【讨论】:

    【解决方案3】:

    你需要像这样使用一个范围:

    class EventManager(models.Manager):
        def bookings_today(self, location_id):
            from datetime import datetime
            now = datetime.now()
            bookings = self.filter(location=location_id, start__lte=now, end__gte=now)
            return bookings
    

    【讨论】:

    • 如果活动的开始和结束都在今天,会发生什么?这不会解决这个问题 - 这可能是一个 headdesk 时刻,但放置 end__gte=today 和 start__lte=today 会解决这个问题吗?
    • 是的,你是对的。应该使用 end__gte=today 和 start__lte=today。
    • 对,这实际上不起作用,因为开始日期可能在今天开始之前或之后,并且 date.today() 似乎与 datetime 对象不匹配选择过程中的平等。
    • @jvc26:当您与日期(而不是日期时间)进行比较时,Django 本质上是在 00:00 到 23:59 的范围内进行。我自己做过无数次,所以我知道它有效。如果您对 Aidas 的代码有疑问,那么还有其他一些问题在起作用。
    • @ChrisPratt 但在这里我们将日期时间 (datetime.now()) 与日期时间 (start_date) 进行比较,我认为这会使时间非常相关?
    【解决方案4】:

    timezone.localtime(timezone.now()).date() 为您提供正确的日期。

    获取今天发生的事件(start今天):

    from django.utils import timezone
    
    class EventManager(models.Manager):
        def bookings_today(self, location_id):
            t = timezone.localtime(timezone.now())
            bookings = self.filter(location=location_id, start__year = t.year,
                start__month = t.month, start__day = t.day, )
    

    【讨论】:

      【解决方案5】:

      我认为 exclude 是你的朋友!

      today = datetime.date.today()
      tomorrow = today + datetime.timedelta( days = 1 )
      self.filter( location = location_id ).exclude( end_date__lt = today ).exclude( start_date__gte = tomorrow )
      

      【讨论】:

        【解决方案6】:

        这个怎么样:pub_date__gte=datetime(2005, 1, 1)?使用_gte__lte 以链式方式限制一天内开始和结束。

        可能类似于self.filter(start__gte=datetime(2005, 1, 1)).filter(end__lte=datetime(2005, 1, 1))lte 代表小于或等于,gte 代表大于或等于。

        我在django doc找到它。

        【讨论】:

          【解决方案7】:

          我有一个建议

          class Car:
                name = models.CharField()
                launched_date = models.DateTimeField()
          

          按今天的日期过滤 datetime 字段非常困难。 即使您使用 timezone.now() - 您也不会得到正确的输出。 因为 timezone.now() 也有时间。

          datetime 字段有时间,因此即使您提供正确的日期,时间也不会匹配。

          所以

          最好使用日期字段进行基于日期的过滤

          class Car:
                name = models.CharField()
                launched_date = models.DateField()
          

          问题的答案:-

             from django.utils.timezone import datetime 
              today = datetime.today()
              events_for_today = Event.objects.filter(start_date__year=today.year,
                                  start_date__month=today.month,
                                   start_date__day=today.day)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-06-13
            • 2021-08-29
            • 1970-01-01
            • 2022-10-13
            • 1970-01-01
            • 2012-08-21
            • 2021-08-27
            相关资源
            最近更新 更多