Django: Исправьте проблему порядка в списке объектов
У меня есть функция, которая получает результаты queryset из базы данных и выполняет некоторые манипуляции.
Когда я получаю результаты этого списка, порядок каким-то образом меняется.
И именно эта функция заставляет порядок измениться: schedules = list(set(schedule_list) - set(excluded_schedules))
Так что я объясню точно:
Я хочу отобразить доступность специалиста для записи на прием. У этого специалиста есть список свободных мест.
Когда посетитель загружает страницу профиля специалиста, Django делает запрос, чтобы получить все временные интервалы специалиста, затем получает все существующие записи на прием, затем удаляет забронированные расписания из общего количества расписаний, чтобы отобразить оставшиеся (доступные расписания). Пока все хорошо?
Итак, код следующий (отредактирован для получения конфиденциальной информации):
def get_home_schedules(date, professional):
day = get_day_by_date(date)
try:
schedules = Schedule.objects.filter(professional=professional, day=day, stype="Home").order_by('timefrom')
excluded_schedules = []
schedule_list = []
for s in schedules:
new_appointments = s.appointments.filter(schedule=s, date=date, status='New')
confirmed_appointments = s.appointments.filter(schedule=s, date=date, status='Confirmed')
appointments = chain(new_appointments,confirmed_appointments)
schedule_list.append(s)
if appointments:
for a in appointments:
excluded_schedules.append(a.schedule)
schedules = list(set(schedule_list) - set(excluded_schedules))
return schedules
except:
return None
Модель расписания:
class Schedule(models.Model):
professional = models.ForeignKey(d, on_delete=models.CASCADE)
timefrom = models.CharField(max_length=5, choices=HOURTIME, default="00:00")
timeto = models.CharField(max_length=5, choices=HOURTIME, default="00:00")
day = models.CharField(max_length=8, choices=DAYS, default="Monday")
stype = models.CharField(max_length=10, choices=APPOINTMENT_TYPE, default='Office')
posted = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Availability"
verbose_name_plural = "Availabilities"
constraints = [
models.UniqueConstraint(fields=['professional', 'timefrom', 'day'], name='unique schedule')
]
def __str__(self):
return '%s (%s - %s - %s)' % (self.professional, self.day, self.timefrom, self.timeto)
Типы назначений следующие: Офис, Онлайн, Дома
Проблема заключается в том, что у меня есть 3 различные функции, которые получают доступные расписания, по одной для каждого типа назначений, и функция работает без проблем в типах Office и Online, но имеет проблему порядка в типе Home.
<Спасибо!
А python set - это неупорядоченная коллекция объектов, что означает, что порядок может измениться, когда вы создаете список расписаний, как показано ниже:
schedules = list(set(schedule_list) - set(excluded_schedules))
Вы должны удалить .order_by('timefrom')
при получении исходного набора запросов (поскольку порядок не будет гарантирован в любом случае), и добавить его в операторе возврата. Например:
schedules = list(set(schedule_list) - set(excluded_schedules))
return Schedule.objects.filter(id__in=schedules).order_by('timefrom')
Когда вы делаете
schedules = list(set(schedule_list) - set(excluded_schedules))
порядок теряется (поскольку set
являются неупорядоченными).
После этого вы можете просто пересортировать (и при этом избавиться от .order_by()
, поскольку это не имеет значения):
schedules = sorted(
set(schedule_list) - set(excluded_schedules),
key=lambda s: s.timefrom,
)
Вы также можете оптимизировать это до 2 запросов с помощью
day = get_day_by_date(date)
schedules = Schedule.objects.filter(professional=professional, day=day, stype="Home").order_by('timefrom')
conflicting_appointment_schedule_ids = set(Appointment.objects.filter(
schedule__in=schedules,
status__in=["New", "Confirmed"],
date=date,
).values_list("schedule_id", flat=True))
return [sched for sched in schedules if sched.id not in conflicting_appointment_schedule_ids]
и я уверен, что одиночный запрос тоже возможен.