我正在努力在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
我是否需要编写一整套不同的选项或者是否有更简单优雅的方法?
答案 0 :(得分:24)
您需要两个不同的datetime
阈值 - today_start
和today_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)
(PS DateTimeField
{而非DateField
名为foo_date
令人恼火的误导 - 只考虑start
和end
...)
答案 1 :(得分:6)
你需要像这样使用范围:
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
答案 2 :(得分: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 :(得分:1)
这个怎么样: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找到了它。
答案 4 :(得分:0)
我认为排除是你的朋友!
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 )
答案 5 :(得分:0)
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, )
答案 6 :(得分:0)
我有一个建议
class Car:
name = models.CharField()
launched_date = models.DateTimeField()
通过今天的日期过滤日期时间字段是非常困难的。 即使你使用 timezone.now() - 你也不会得到正确的输出。 因为 timezone.now() 也有时间。
datetime 字段有时间,因此即使您提供正确的日期,时间也不会匹配。
所以
<块引用>最好使用datefield进行基于日期的过滤
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)