I'm trying to construct a moderately complex filter in the Django ORM, and I'm not sure if I could do it more efficiently.
My app lets users search for shoes in a particular size. So if they select a size (or multiple sizes), I look for all the shoes available in that size.
This is my model structure. There's an object for each shoe (Shoe
), an object for each size (ShoeSize
) (standardised across manufacturers), and an object (ShoeSizeAvailable
) that only gets created if a particular shoe is available in a particular size.
class Shoe(ClothingItem):
price = models.FloatField(null=True,blank=True,db_index=True) ...
class ShoeSize(models.Model):
code = models.CharField(max_length=8) ...
class ShoeSizeAvailable(models.Model):
shoe = models.ForeignKey(Shoe)
size = models.ForeignKey(ShoeSize)
And this is how I currently do the filtering:
kwargs = {}
args = ()
if query['price_from']:
kwargs['price__gte'] = float(query['price_from'][0])
# Lots of other filters here...
results = Shoe.objects.filter(*args, **kwargs)
if query['size']:
# The query is a list like [6, 6.5]
# Get all potential ShoeSizeAvailable matches.
sizes = ShoeSizeAvailable.objects.filter(size__code__in=query['size'])
# Get only the ones that apply to the current shoe.
shoe_ids = sizes.values_list('shoe', flat=True)
# Filter the existing shoe results for these values.
results = results.filter(id__in=shoe_ids)
Is this the most efficient way? I'm concerned that __in
queries might be inefficient with long lists like these.
I would do this this way: