Django Query calculate date with `relativedelta` error: can't adapt type 'relativedelta'

Я столкнулся с непростой проблемой и не смог найти решение в Интернете. Я надеюсь, что кто-нибудь здесь поможет мне найти "чистый" способ сделать это.

Вот моя текущая функция для получения всех просроченных кредитов (она работает):

queryset = super().get_queryset().filter(is_active=True)
expired_loans_ids = {loan.pk for loan in queryset if loan.is_expired()}
expired_loans = queryset.filter(pk__in=expired_loans_ids)
return expired_loans

Однако это не идеальный вариант, поскольку я не просто использую запрос, а должен сначала получить все данные. Я хотел сделать примерно следующее:

from dateutil.relativedelta import relativedelta

queryset = super().get_queryset().filter(is_active=True)
expired_loans = queryset.annotate(
    expiration_date=ExpressionWrapper(
        F('timestamp') + relativedelta(months=1),
        output_field=DateField()
    )
).filter(expiration_date__lt=Now())
return expired_loans

Но при использовании relativedelta я получаю эту ошибку: django.db.utils.ProgrammingError: can't adapt type 'relativedelta'

Это работает с timedelta, но каждый месяц имеет разное количество дней...

Как я могу добиться чего-то подобного?

Действительно не может, так как Django нужно найти выражение для этого, а оно не знает relativedelta.

Но, скорее всего, это все равно не нужно. Мы можем вычесть теперь:

from dateutil.relativedelta import relativedelta
from django.utils.timezone import now

queryset = (
    super()
    .get_queryset()
    .filter(is_active=True, timestamp__lt=now() - relativedelta(months=1))
)

или другой способ - просто ввести год, месяц и день:

from django.utils.timezone import now

y, m, d, *__ = now().timetuple()

m -= 1
if m < 1:
    m = 12
    y -= 1

queryset = (
    super()
    .get_queryset()
    .filter(
        Q(timestamp__year__lt=y)
        | Q(timestamp__year=y, timestamp__month__lt=m)
        | Q(timestamp__year=y, timestamp__month=m, timestamp__day__lt=d),
        is_active=True,
    )
)

The relative deltas are a bit complicated w.r.t. the 31st of a month for example. If you for example add a month on August, 31th, it will return September 30th, the question is if that is the expiration date.

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