Django queryset - exclude True values

I am tryig to build a queryset where only the true values are added.

Models

Models
reference = models.CharField(validators=[MinLengthValidator(15)], max_length=25, primary_key=True)
h0730 = models.BooleanField(default=False)
h0800 = models.BooleanField(default=False)
h0830 = models.BooleanField(default=False)
h0900 = models.BooleanField(default=False)
h0930 = models.BooleanField(default=False)
h1000 = models.BooleanField(default=False)
h1030 = models.BooleanField(default=False)
h1100 = models.BooleanField(default=False)
h1130 = models.BooleanField(default=False)
h1200 = models.BooleanField(default=False)
h1230 = models.BooleanField(default=False)
h1300 = models.BooleanField(default=False)
h1330 = models.BooleanField(default=False)
h1400 = models.BooleanField(default=False)
h1430 = models.BooleanField(default=False)
h1500 = models.BooleanField(default=False)
h1530 = models.BooleanField(default=False)
delivery_date = models.CharField(max_length=8)
is_cancelled = models.BooleanField(default=False)

Views

taken_slots = Order.objects.filter(delivery_date__exact=delivery_date).filter(reference__icontains=code).filter(is_cancelled=False)

slots_remaining = ['h0730', 'h0800', 'h0830', 'h0900', 'h0930', 'h1000', 'h1030', 'h1100', 'h1130', 'h1200', 'h1230', 'h1300', 'h1330', 'h1400', 'h1430', 'h1500', 'h1530']

for slot in taken_slots:
    if slot.h0730 and 'h0730' in slots_remaining:
        slots_remaining.remove('h0730')
    if slot.h0800 and 'h0800' in slots_remaining:
        slots_remaining.remove('h0800')
        ...
        ...

The above for loop works as is expected but I am trying to optimize the process. For example if there are 100 references for the day, "taken_slots" will will be iterated 100 times.

The expected output after the for loop completes is that the "slots_remaining" list will only have the False values remaining, e.g.

ref1 = h0730 and h0930 is True and every other slot False
ref2 = h0900 is True and every other slot False
ref3 = h1030 is True and every other slot False
ref4 = h1230 is True and every other slot False
ref5 = h1300 and h1330 is True and every other slot False
ref6 = h1500 is True and every other slot False

If h0730, h0900, h0930, h1030, h1230, h1300, h1330, h1500 from 6 references are True.
slots_remaining must remain with ['h0800', 'h0830', 'h1000', 'h1100', 'h1130', 'h1200', 'h1400', 'h1430', 'h1530']

Is there a way to build slots_remaining list directly from the taken_slots query or atleast avoid the for loop. I have seen examples of distinct, annotate and union but am probably doing it wrong asI haven't managed to get it working.

I didn't get what you said in the last paragraph. but you can use the exclude function like this:

exclude_param = {item: True for item in slots_remaining}
taken_slots = taken_slots.exclude(**exclude_param)

I hope it works for you. if not, explain more about your last paragraph.

I don't see why you enumerate 100 times, you can work with a set and thus work with:

slots_remaining = {
    'h0730',
    'h0800',
    'h0830',
    'h0900',
    'h0930',
    'h1000',
    'h1030',
    'h1100',
    'h1130',
    'h1200',
    'h1230',
    'h1300',
    'h1330',
    'h1400',
    'h1430',
    'h1500',
    'h1530',
}


for slot in taken_slots:
    slots_remaining -= {name for name in slot_remaining if getattr(slot, name)}

this will enumerate once over the taken_slots, and for each slot, only check the remaining once each time. At the end of the loop, the remaining once are still in slots_remaining. It will thus query the database once.

But the modeling does not look very effective: databases usually should be designed lineary. This mean that two items are of the same "category", don't store these in different columns, but in different rows. This makes querying, especially in this case a lot more convenient.

Back to Top