覆盖 Django DateField 上的查询以更改搜索日期

问题描述 投票:0回答:2

我在 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 进行子类化?

(注意上面的代码是输入的,简化的,可能包含错误,但它在我的实际代码中有效)

python django django-queryset
2个回答
1
投票

我们可以将

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)}]>

我没有对此进行广泛的测试,但我想大部分功能都已涵盖。


0
投票

在数据库级别,您可以根据 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()
© www.soinside.com 2019 - 2024. All rights reserved.