Как можно отфильтровать список людей на момент события, прошло n лет между их датой рождения и датой события? Каким образом можно применить фильтрацию по возрасту к двум связанным моделям в Django? Можно ли использовать какой-либо другой метод, кроме сериализации, для применения этой фильтрации в Django queryset?
Для вычисления разницы между значениями полей `DateField` из двух моделей и отфильтрования списка людей на момент события, можно воспользоваться функцией `filter()` и оператором разности `F()` в Django. Пример кода: ```python from django.db.models import F from datetime import timedelta # Предположим, у модели Person есть поле birth_date, а у модели Event - поле event_date # Разница между датами рождения и датой события difference = timedelta(days=365 * n) # где n - количество лет # Фильтрация по возрасту на момент события people = Person.objects.filter(birth_date__lte=F('event_date') - difference) ``` Этот код найдет всех людей, чей возраст на момент события составляет не менее `n` лет. Что касается применения фильтрации по возрасту к двум связанным моделям в Django, можно использовать аннотации (annotations) для вычисления возраста на основе даты рождения и применения фильтрации к связанным объектам. Пример использования аннотаций для вычисления возраста и фильтрации по нему: ```python from django.db.models import F, ExpressionWrapper, DateTimeField from django.db.models.functions import ExtractYear from datetime import datetime # Аннотация для вычисления возраста age_annotation = ExpressionWrapper( ExtractYear(F('event_date')) - ExtractYear(F('person__birth_date')), output_field=DateTimeField() ) # Фильтрация по возрасту events = Event.objects.annotate(age=age_annotation).filter(age__gte=n) ``` Этот код найдет все события, где возраст человека (связанного с событием) на момент события больше или равен `n` лет. В Django queryset также можно использовать метод `extra()` для применения фильтрации без сериализации, хотя это не всегда рекомендуется из-за возможных проблем с безопасностью и совместимостью.
Все же удалось найти способ, уверен кому-то пригодится, в отчетности это один из частых случаев. Я не большой специалист в 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 p.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 p.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 можно сделать. Кто знает ответ, обязательно напишите здесь.