I have a function that gets queryset results from the database and does some manipulations.
When I get the results of that list, somehow the order is changed.
And exactly this is the function that makes the order change: schedules = list(set(schedule_list) - set(excluded_schedules))
So I will explain exactly:
I want to display the availability of a professional for booking an appointment. This professional has a list of available slots.
When the visitor loads the professional profile page, Django makes a query to get all time slots of the professional, and then gets all the existing appointments, then proceeds to remove the booked schedules from the total schedules, to display the rest (the available schedules). So far so good?
So, the code is the following (edited for sensitive information):
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
The schedule model is:
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)
The appointment types are: Office, Online, Home
The issue I have is that I have 3 different functions, that get the available schedules, one for each appointment type, and the function works without any problems in the Office and Online types, but has the issue of order in the Home type.
The order might be because of the hour, please tell me if it's true or not (even thought I do not think it's the case because the order doesn't get messed up in the other cases).
Thank you!
CodePudding user response:
A python set is an unordered collection of objects, meaning that the order might change when you create the list of schedules like below:
schedules = list(set(schedule_list) - set(excluded_schedules))
You should delete the .order_by('timefrom')
when retrieving the initial queryset (as the order will not be guaranteed anyways), and add it in the return statement. For example:
schedules = list(set(schedule_list) - set(excluded_schedules))
return Schedule.objects.filter(id__in=schedules).order_by('timefrom')
CodePudding user response:
When you do
schedules = list(set(schedule_list) - set(excluded_schedules))
the order is lost (since set
s are unordered).
You can just re-sort afterwards (and with that, get rid of the .order_by()
since it doesn't matter):
schedules = sorted(
set(schedule_list) - set(excluded_schedules),
key=lambda s: s.timefrom,
)
You can also optimize this to exactly 2 queries with
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]
and I'm sure a single query would be possible too.