Фильтрация запросов Django по номеру недели ISO

У меня есть модель, содержащая datefield. Я пытаюсь получить набор запросов этой модели, который содержит текущую неделю (начинается в понедельник).

Так как Django datefield содержит простую модель datetime.date, которую я решил фильтровать с помощью .isocalendar(). Логически это именно то, что я хочу без каких-либо дополнительных сравнений и вычислений в текущий день недели.

Итак, что я хочу сделать по существу, это выражение force .filter, которое должно вести себя в этой логике:

if model.date.isocalendar()[2] == datetime.date.today().isocalendar()[2]
    ...

Но как написать это внутри оператора фильтра? .filter(model__date__isocalendar=datetime.date.today().isocalendar()) даст неправильные результаты (то же самое, что и сегодня не на этой неделе).

Как копать true http://docs.python.org/library/datetime.html Я не заметил никаких других вариантов дня недели...

Примечание к документации:

date.isocalendar() Возвращает 3-х кортеж (год ISO, номер недели ISO, ISO день недели).

Update:

Хотя мне не понравилось решение использовать диапазоны, но это лучший вариант. Однако в моем случае я сделал переменную, которая знаменует начало недели и просто выглядит более или равнозначной, потому что если я ищу соответствия для текущей недели. В случае, если вы укажете номер недели, для этого потребуются оба конца.

today = datetime.date.today()
monday = today - datetime.timedelta(days=today.weekday())

... \
.filter(date__gte=monday)

Ответ 1

Вы не сможете это сделать. Помните, что это не просто проблема того, что поддерживает Python, Django должен передать фильтр в базу данных, а база данных не поддерживает такие сложные вычисления даты. Вы можете использовать __range, хотя, с датой начала и окончания.

Ответ 2

(Этот ответ должен работать только для postgres, но может работать и для других баз данных.)

Быстрое и элегантное решение этой проблемы заключается в определении этих двух настраиваемых трансформаторов:

from django.db import models
from django.db.models.lookups import DateTransform

@models.DateTimeField.register_lookup
class WeekTransform(DateTransform):
    lookup_name = 'week'


@models.DateTimeField.register_lookup
class ISOYearTransform(DateTransform):
    lookup_name = 'isoyear'

Теперь вы можете запросить по неделям следующим образом:

from django.utils.timezone import now
year, week, _ = now().isocalendar()

MyModel.objects.filter(created__isoyear=year, created__week=week)

За кулисами объект Django DateTransform использует функцию postgres EXTRACT, которая поддерживает week и isoyear.

Ответ 3

ExtractWeek был введен в Django 1.11 для фильтрации на основе номера isoweek.

Для Django 1.10 и более поздних версий следующее решение работает для фильтрации по iso number week в базе данных postgres:

from django.db.models.functions import Extract
from django.db import models
@models.DateTimeField.register_lookup
class ExtractWeek(Extract):
    lookup_name = 'week'

Теперь выполните запрос следующим образом

queryset.annotate(week=ExtractWeek('date'))\
            .filter(week=week_number)