Django: efficient filtering in the ORM across Fore

2019-08-11 05:18发布

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.

1条回答
我想做一个坏孩纸
2楼-- · 2019-08-11 05:36

I would do this this way:

if query['size']:
    results = results.filter(shoesizeavailable__size__code__in=query['size'])
查看更多
登录 后发表回答