Фильтровать запросы 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

Вернуться на верх