@bagrovykt

Django filter — вычисляемая разница datefield-полей из двух моделей?

Есть две связанные модели
# люди
class Humans(models.Model):
    ...
    name=models.CharField()
    birthdate=models.DateField()
# события
class Events(models.Model):
    ...
    eventDate=models.DateField()
    human=models.ForeignKey(Humans, on_delete=models.PROTECT)

Задача - вернуть список событий с фильтрацией по возрасту на момент этого события, то есть технически это список событий, в которых между датами eventDate и birthdate прошло n лет.?
Вроде бы несложно, но на деле нужно вычитать даты из разных моделей.
Это довольно просто сделать в сериализаторе, но как потом отфильтровать по получившемуся полю ума не приложу. Может быть есть способ прописать в фильтре queryset или совсем какой-то иной способ существует?
  • Вопрос задан
  • 58 просмотров
Пригласить эксперта
Ответы на вопрос 1
@bagrovykt Автор вопроса
Все же удалось найти способ, уверен кому-то пригодится, в отчетности это один из частых случаев. Я не большой специалист в django, да и по python в целом, поэтому задачку решал в запроснике pma, в mysql есть прекрасный функционал для арифметики дат. В общем это по сути объединение таблиц и фильтрация по двум его полям, чего добиться в django не могу.
SELECT e.id from appname_events as e left join appname_humans as h ON e.human_id=h.id where h.birthdate between DATE_SUB(e.eventDate, interval AGEMAX year) and DATE_SUB(e.eventDate, interval AGEMIN year) ORDER BY e.eventDate DESC

Запрос получился тяжелым, но похоже это меньшее из зол. Выбор только одного столбца дает выиграть время втрое против выборки всех столбцов. Я не уверен как django потом делает свою магию, но в итоге все равно сериализуются "правильные" объекты со всеми полями.
#вьюсет
...
def get_queryset(self):
   # получение и валидация ageMin, ageMax из self.request.query_params
   ...
   # выборка и сортировка
   query="SELECT e.id from appname_events as e left join appname_humans as h ON e.human_id=h.id where h.birthdate between DATE_SUB(e.eventDate, interval " + ageMax + " year) and DATE_SUB(e.eventDate, interval " + ageMin+ " year) ORDER BY e.eventDate DESC"
   queryset=Events.objects.raw(sql)
   return queryset

Работает нормально, учитываются високосные года. Из 800 событий и 600 людей на запрос уходит от 0.005 до 0.02 сек, в зависимости от выборки.

Но честно говоря, выглядит костылем, мне все еще кажется, что это как-то средствами django orm можно сделать. Кто знает ответ, обязательно напишите здесь.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы