2012-03-19 2 views
3

Чтобы сделать мой вопрос более понятным, вот пример.Django: Можно ли достичь того же, что и sql существует?

Есть две модели:

class A(models.Model): 
    name = models.CharField(max_length = 10) 

class B(models.Model): 
    a = models.ForeignKey(A) 
    name = models.CharField(max_length = 10) 

Таким образом, в этом примере, A и B являются одной-к-многим. Теперь предположим, что я хотел бы сделать следующий запрос: найти A, у которого есть хотя бы один B как дочерний. В sql, очевидно, я должен использовать условие существования. Можно ли добиться того же результата с ормом?

Я провел некоторое исследование по этому вопросу, но не могу найти идеальное соответствие запросу sql. Наиболее близким решением является как:

A.objects.filter(b__pk__gt = 0).distinct() 

Но это еще далеко не существует пункт в SQL и не может быть столь же эффективным, как существует.

ответ

1

Ниже будут выбраны все A S, которые имеют один или более связанных B S:

A.objects.filter(b__isnull=False) 

Переключение его b__isnull=True будет выбрать только A S, которые не имеют B сек, связанные с ними.

+0

Итак, с b__isnull = False, мне больше не нужно добавлять четкие выражения? И это условие bona fide exists в sql? –

+0

Вам не нужен отдельный, но я не уверен, какой запрос он выполняет точно. Это, однако, лучшее, что вы собираетесь делать с ORM Django. В противном случае просто используйте SQL-запрос с 'raw'. –

+0

Получите правильный ответ, прежде чем уходить с пути для оптимизации. Если вы действительно должны смотреть под обложками SQL-запроса ORM: 'import django; django.db.connection.queries' из './manage.py shell'. – istruble

1

Фактически (если я не неправильно понял, что вы пытаетесь сделать) с простым sql простым левым соединением будет путь, а не предложение EXISTING.

Ваш QuerySet прекрасно работает без .distinct()

Я рекомендую вам взглянуть на запросы, которые Джанго ORM генерирует, так что вы можете увидеть, что происходит и на самом деле запустить ПРОАНАЛИЗИРУЙТЕ/EXPLAIN вместо угадывая выступления.

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

+0

+1 для панели инструментов отладки. Если вы посмотрите на запрос, вы, вероятно, обнаружите, что 'A.objects.exclude (b__isnull = True)' выполняет LEFT OUTTER JOIN и '... filter (b__isnull = False)' выполняет INNER JOIN. – istruble

+0

@istruble действительно, соединение - это путь для такого запроса –

+0

Извините. Но я должен не согласиться с вами в вашем существующем против простого комментария левого соединения здесь. Мой пример просто ищет A, у которого есть B-ребенок. У меня нет фильтра на B. Так что существует или его замена - естественный выбор. –

Смежные вопросы