Django / Python: Сортировка QuerySet по полю в первом экземпляре отношения foreignkey
У меня есть следующие 2 модели, модель Lesson
, которая может иметь несколько дат начала / окончания - каждая со своей собственной моделью Date
.
class Lesson(models.Model):
name = models.Charfield()
(...)
class Date(models.Model):
meeting = models.ForeignKey(
Lesson,
verbose_name="dates",
on_delete=models.CASCADE,
)
start_date = models.DateTimeField(
blank=True,
null=True,
)
end_date = models.DateTimeField(
blank=True,
null=True,
)
Для нашего проекта нам нужно упорядочить Lessons
по start_date
их самому раннему Date
экземпляру.
Например, если у меня есть следующие данные:
MEETING A:
DATE_1a: 2022-11-01 --> 2022-11-02
DATE_2a: 2022-12-10 --> 2022-12-11
MEETING B:
DATE_1b: 2022-11-03 --> 2022-11-04
DATE_2b: 2022-11-05 --> 2022-11-06
Затем набор запросов должен вернуть [<MEETING A>, <MEETING B>]
на основе start_date
значений экземпляров DATE_1a/b
. (2022-11-01
раньше, чем 2022-11-03
, все остальные даты игнорируются)
Однако то, что, как я думал, будет относительно простым запросом, оказалось довольно коварной проблемой. Мой первоначальный подход метода по умолчанию order_by
использовал все экземпляры Date
, присоединенные к Meeting
(и, что еще хуже, возвращал отдельный результат Meeting
для каждого экземпляра Date
)
qs.order_by(F("dates__start_date").asc(nulls_first=True))
Однако я не смог придумать запрос для выполнения того, что нам нужно. Мое текущее рабочее решение заключается в использовании целой кучи кода python, чтобы вместо этого сделать:
ordered_meetings = []
meeting_dict = {}
for meeting in qs:
first_date = meeting.dates.first()
if not meeting_dict.get(meeting.id):
meeting_dict[meeting.id] = first_date.start_date
А затем упорядочиваем dict на основе значений дат, используя ID/KEYS для получения Meeting
экземпляров и добавления их в ordered_meetings
список.
Но это настолько запутанный (и гораздо более медленный) подход, что я чувствую, что я, должно быть, что-то упускаю. Кто-нибудь знает более лаконичный метод достижения того, что мы хотим?
Полагаю, вам нужен мин?
Что-то вроде (не проверено):
Meeting.objects.annotate(first_date=Min('dates__start_date')).order_by('first_date')