我在 Django 中有一个代表一周的模型。我想让有人输入任何日期并让模型自动保存一周的开始时间。这很简单,只需覆盖保存即可。
class Week(models.Model):
start_date = models.DateField()
def save(self):
self.start_date = self.start_date - datetime.timedelta(days=date.weekday())
但我也希望有人能够查询任何一天并获取一周。例如,我希望有人这样做:
this_week = Week.objects.filter(start_date=date.today())
今天是星期三,并获取设置一周开始日期的周对象。它需要在任何日期都有效,而不仅仅是今天。
我知道我们可以在管理器中覆盖 get_queryset,但是有没有办法编辑实际搜索的内容?我能找到的每个管理器示例都只是以静态方式更改了查询集。或者我最好的选择是尝试对 DateField 进行子类化?
(注意上面的代码是输入的,简化的,可能包含错误,但它在我的实际代码中有效)
我们可以将
DateField
子类化,以便每次将日期时间清理到一周的开始。这看起来像:
from django.db.models.fields import DateField
from datetime import timedelta
class WeekField(DateField):
def to_python(self, value):
value = super().to_python(value)
if value is not None:
value -= timedelta(days=value.weekday())
return value
然后我们可以用
WeekField
进行创建、过滤等操作。因此,我们可以在 Week
模型中指定这一点:
class Week(models.Model):
week = WeekField()
然后例如使用
.get_or_create(…)
:
>>> from datetime import date
>>> Week.objects.get_or_create(week=date.today())
(<Week: Week object (1)>, True)
>>> Week.objects.get_or_create(week=date.today())
(<Week: Week object (1)>, False)
按周过滤:
>>> Week.objects.filter(week=date(2021, 8, 31))
<QuerySet [<Week: Week object (1)>]>
>>> Week.objects.filter(week=date(2021, 8, 2))
<QuerySet []>
通过
.values()
查看本周的开始:
>>> Week.objects.values()
<QuerySet [{'id': 1, 'week': datetime.date(2021, 8, 30)}]>
我没有对此进行广泛的测试,但我想大部分功能都已涵盖。
在数据库级别,您可以根据 start_date 进行排序,而不是默认的
primary_key
class Week(models.Model):
start_date = models.DateField()
class Meta:
ordering = ['start_date']
从这里,可以相当直接地找到您想要的一周。
week = Week.objects.filter(start_date__lte=date.today()).first()
使用
Meta
的替代方法是在查询中简单地使用 order_by
。
week = Week.objects.filter(start_date__lte=date.today()).order_by('start_date').first()