Чем заменить DateModifierNode в новых версиях Django

Я хочу сделать запрос на основе двух полей модели, даты, смещения на int, используемых в качестве timedelta

model.objects.filter(last_date__gte=datetime.now()-timedelta(days=F('interval')))

не подходит, так как выражение F () не может быть передано в timedelta

Немного покопавшись, я обнаружил DateModifierNode - хотя кажется, что он был удален в этой фиксации: https://github.com/django/django/commit/cbb5cdd155668ba771cad6b975676d3b20fed37b (из этого устаревшего вопроса SO Django: использование аргументов F в datetime.timedelta внутри запроса)

в коммите упоминается:

Запросы .dates () были реализованы с использованием пользовательских классов Query, QuerySet и Compiler. Вместо этого реализуйте их с помощью выражений и API-интерфейсов преобразователей баз данных.

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


person Chozabu    schedule 01.08.2016    source источник
comment
Вам не нужно изменять структуру модели и добавлять ее вручную. См. это.   -  person Naresh Chaudhary    schedule 22.02.2017


Ответы (2)


В Django 1.10 есть более простой способ сделать это, но вам нужно немного изменить модель: используйте DurationField. Моя модель выглядит следующим образом:

class MyModel(models.Model):

    timeout = models.DurationField(default=86400 * 7)  # default: week
    last = models.DateTimeField(auto_now_add=True)

и запрос на поиск объектов, где last был до now минус timeout:

MyModel.objects.filter(last__lt=datetime.datetime.now()-F('timeout'))
person Alex    schedule 14.12.2016
comment
Не проверял это, но если у вас есть;) выглядит гораздо более приятным решением! Скоро обновлю django - person Chozabu; 16.12.2016

Ах, ответ из документов: https://docs.djangoproject.com/en/1.9/ref/models/expressions/#using-f-with-annotations

from django.db.models import DateTimeField, ExpressionWrapper, F

Ticket.objects.annotate(
    expires=ExpressionWrapper(
        F('active_at') + F('duration'), output_field=DateTimeField()))

что должно сделать мой исходный запрос похожим на

model.objects.annotate(new_date=ExpressionWrapper(F('last_date') + F('interval'), output_field=DateTimeField())).filter(new_date__gte=datetime.now())
person Chozabu    schedule 01.08.2016
comment
серьезно возможно для F('last_date') + F('interval'), а вывод - datetimefield? и он увеличился в днях так же, как timedelta(days=interval)? - person Roel; 16.01.2017
comment
Вычитание числа из даты для меня не работает, так как это не распознается как вычитание дней. Я использую mysql. - person Johann; 12.07.2019