Фильтровать запросы Django по неделям месяца?
В запросе Django, как бы вы отфильтровали по неделе временной метки в пределах месяца?
Есть встроенный аксессор week, но он относится к неделе года, например, 1-52. Насколько я могу судить, других встроенных опций нет.
Единственный способ, который я вижу для этого - вычислить диапазон дат начала и конца недели, а затем отфильтровать его обычными средствами.
Так что я использую функцию типа:
def week_of_month_date(year, month, week):
"""
Returns the date of the first day in the week of the given date's month,
where Monday is the first day of the week.
e.g. week_of_month_date(year=2022, month=8, week=2) -> date(2022, 8, 7)
"""
assert 1 <= week <= 5
assert 1 <= month <= 12
for i in range(1, 32):
dt = date(year, month, i)
_week = week_of_month(dt)
if _week == week:
return dt
и затем для расчета, скажем, для 3-й недели июля 2022 года, я бы сделал:
start_date = week_of_month_date(2022, 7, 3)
end_date = week_of_month_date(2022, 7, 3) + timedelta(days=7)
qs = MyModel.objects.filter(created__gte=start_date, created__lte=end_date)
Есть ли более простой или эффективный способ сделать это с помощью Django ORM или SQL?
Самый простой способ сделать это с помощью объектов datetime
заключается в простом вычитании значения недельного года текущей даты из значения недельного года для 1-го дня (или 1-й недели) месяца.
Для этого можно использовать функцию .isocalendar()
:
dt.isocalendar[1] - dt.replace(day=1).isocalendar()[1] + 1
В принципе, если неделя равна 46 и это означает, что первая неделя - это неделя 44, то результирующий вывод должен быть 2.
UPDATE
Я неправильно понял вопрос, ответ ясен ниже. Однако, возможно, вы захотите пересмотреть свою функцию, основываясь на моих комментариях выше.
Если подумать, если у вас есть объект datetime, вы можете получить неделю изокалендаря и фильтровать, используя это, следующим образом:
MyModel.objects.filter(created__week=dt.isocalendar()[1])
dt.isocalendar()
возвращает по сути кортеж из 3 целых чисел, [0]
- год, [1]
- неделя изо (1-52 или 53) и [2]
- день недели (1-7).
Согласно документации здесь:
https://docs.djangoproject.com/en/4.1/ref/models/querysets/#week
Есть встроенный фильтр для isoweek из коробки :)
Однако, фильтрация по "неделе месяца" невозможна в рамках "из коробки".
Вы можете рассмотреть возможность написания собственного объекта выражения запроса, который принимает объект isocalendar и преобразует его? Но я думаю, что вам лучше преобразовать объект времени и использовать фильтр isoweek.
Вот небольшой пост в блоге, который поможет вам начать, если вы действительно хотите это сделать:
https://dev.to/idrisrampurawala/writing-custom-django-database-functions-4dmb