2014-10-16 3 views
3

Каков предпочтительный способ фильтрации запроса, заданного с помощью '__in' в Django?Django ORM values_list с производительностью фильтра __in

providers = Provider.objects.filter(age__gt=10) 
consumers = Consumer.objects.filter(consumer__in=providers) 

или

providers_ids = Provider.objects.filter(age__gt=10).values_list('id', flat=True) 
consumers = Consumer.objects.filter(consumer__in=providers_ids) 

ответ

7

Они должны быть полностью эквивалентны. Под капотом Django оптимизирует оба из них для запроса подзапроса в SQL. Смотрите QuerySet API reference on in:

Это QuerySet будет оцениваться как подвыборки заявление:

SELECT ... WHERE consumer.id IN (SELECT id FROM ... WHERE _ IN _) 

Однако вы можете заставить поиск, основанный на переходе в явных значений первичных ключей, вызвав list на вашем values_list, например, так:

providers_ids = list(Provider.objects.filter(age__gt=10).values_list('id', flat=True)) 
consumers = Consumer.objects.filter(consumer__in=providers_ids) 

Это может быть более производительным в некоторых случаях, например, когда у вас есть несколько поставщиков, но это будет полностью зависеть от того, что ваши данные, как и то, что база данных вы используете. См. Примечание «Рекомендации по производительности» в приведенной выше ссылке.

4

Я согласен с Wilduck. Однако пара нот

Вы можете комбинировать фильтры, такие как они в один, как это:

consumers = Consumer.objects.filter(consumer__age__gt=10) 

Это даст вам тот же набор результатов - в одном запросе.

Вторая вещь, чтобы проанализировать сгенерированный запрос, вы можете использовать предложение .query в конце.

Пример:

print Provider.objects.filter(age__gt=10).query 

бы напечатать запрос ОРМ будет генерирующий для извлечения результирующего набора.