Задать вопрос
@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 или совсем какой-то иной способ существует?
  • Вопрос задан
  • 67 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 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 можно сделать. Кто знает ответ, обязательно напишите здесь.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы
Strikt Москва
от 100 000 до 180 000 ₽
ITK academy Саратов
от 75 000 ₽
Sim-Ba Pay Санкт-Петербург
от 180 000 ₽