Наиболее эффективный запрос Django для получения объектов и связанных с ними - PullRequest
0 голосов
/ 15 июля 2011

У меня есть эта модель:

class Institution(models.Model):
    name = models.CharField(max_length=128, db_index=True)
    aliases = models.ManyToManyField('self', blank=True)

Я хотел бы сделать наиболее эффективный запрос, который возвращает все Institution, где name содержит поисковый термин И их aliases Institution. Я пришел с решением ниже этой работы, но мне было интересно, есть ли более простой / более эффективный способ добиться этого?

base_query = Institution.objects.filter(name__icontains='term')
pk_query = Q(pk__in=base_query)
aliases_query = Q(aliases__in=base_query)
final_query = Institution.objects.filter(pk_query|aliases_query).distinct()

Вот SQL этого запроса:

SELECT DISTINCT `app_institution`.`id`, `app_institution`.`name`
FROM `app_institution` LEFT OUTER JOIN `app_institution_aliases`
ON (`app_institution`.`id` = `app_institution_aliases`.`from_institution_id`)
WHERE (`app_institution`.`id`
IN (SELECT U0.`id` FROM `app_institution` U0 WHERE U0.`name` LIKE %term% )
OR `app_institution_aliases`.`to_institution_id`
IN (SELECT U0.`id` FROM `app_institution` U0 WHERE U0.`name` LIKE %term% ))
ORDER BY `app_institution`.`name` ASC LIMIT 21

UPDATE

Глядя на 2 первых полученных ответа, я думаю, что должен более четко указать, что я хочу в качестве результата.

Я хочу СОЮЗ

  • результаты base_query (Institution, где name содержит поисковый термин)

С

  • aliases каждого из Institution возвращаемых base_query (тезисы aliases 'name не должны содержать поисковый термин).

Сделано неэффективным (но легко понятным) способом, вот так:

base_query = Institution.objects.filter(name__icontains='term')
results= set(base_query)
for institution in base_query:
    results.update(institution.aliases.all())

2-е ОБНОВЛЕНИЕ

Думая об ответе С. Лотта, я наконец-то нашел способ сделать это с помощью двух запросов, которые я объединяю после.

base_query = Institution.objects.filter(name__icontains='term')
results= set(base_query)
aliases_query = Institution.objects.filter(aliases__in=base_query)
results.update(aliases_query)

Я сделал несколько небольших тестов, и это решение занимает примерно половину времени по сравнению с одним большим запросом.

Но то, что я забыл принять во внимание, это влияние на порядок ...

Ответы [ 2 ]

0 голосов
/ 15 июля 2011

это:

Institution.objects.filter(name__icontains='term', aliases__name__icontains='terms')
0 голосов
/ 15 июля 2011

Объединение запросов - как это - сложно.

Важно рассмотреть варианты использования, чтобы убедиться, что действительно необходимо объединить две отдельные коллекции (по имени и псевдониму).) как это.Иногда веб-страница может быть представлена ​​двумя коллекциями, что устраняет необходимость в объединении.

Использование Q объектов для создания "или" условий является одним из способов создания объединения.

Сборкаотдельная коллекция из этих двух запросов - другое решение.

name_query = Institution.objects.filter(name__icontains='term')
aliases_query = Institution.objects.filter(aliases__name__icontains='term')
final_query = list(name_query) + list(aliases_query)

Единственный способ узнать, что лучше, - сравнить альтернативы.«Сложность» текста запроса SQL на самом деле не имеет большого значения, потому что в СУБД так много шагов по оптимизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...