2010-02-17 2 views
9

Скажем, у меня есть два Django модели человека и общества следующим образом: -Джанго ForeignKey с нулевым = True, внутреннее соединение и левое внешнее соединение

class Company(models.Model): 
    name = models.CharField() 

class Person(models.Model): 
    last_name = models.CharField(blank=True) 
    first_name = models.CharField() 
    company = models.ForeignKey(Company, null=True, blank=True) 

Человек может или не может принадлежать к компании.

Я использую MySQL. Я хочу, чтобы все Лица, не принадлежащие какой-либо Компании, то есть Лица, где компания является нулевой.

Если я Person.objects.filter(company__isnull=True) я получаю SQL, который по существу: -

SELECT * FROM PersonTable LEFT OUTER JOIN AgencyTable ON (PersonTable.company_id = AgencyTable.id) WHERE AgencyTable.id IS NULL

Как я могу идти о достижении следующего SQL: -

SELECT * FROM PersonTable INNER JOIN AgencyTable ON (PersonTable.company_id = AgencyTable.id) WHERE AgencyTable.id IS NULL

Из того, что я собираю от чтения списка рассылки Django Users, это было поведение перед QuerySet Refactor.

EDIT - Теперь я вижу богохульство в моем вопросе!

То, что я хочу сказать, я просто хочу, чтобы сделать

SELECT * FROM PersonTable WHERE PersonTable.company_id IS NULL

+0

Ну, если это не делает смысл для вас, это на самом деле является «базовой» запрос, который получает ВНУТРЕННИЙ объединился с другими запросами, и это приводит к странным , повторяющиеся результаты. – chefsmart

+0

Этот вопрос действительно является результатом ментального блока. – chefsmart

ответ

1

Оно должно быть простым:

Person.objects.filter(company_id__isnull=True) 

Обратите внимание на использование company_id который является целым числом по умолчанию поле созданное by ForeignKey

Редактировать

К сожалению, я не использовал django с 0.9.5. Либо я думаю о пред-1.0 поведении, либо я запутываю sqlalchemy и Django ORM. В любом случае, как указано в комментариях, вышеуказанное не работает.

Похоже, что единственный способ получить запрос, который вы хотите в текущем django, - использовать параметр запроса .extra, который содержит весь список предостережений.

Person.objects.extra(where=['company_id IS NULL']) 

Обратите внимание, что это не может быть переносимым на все БД, и она не может работать в сочетании с фильтром(), и любое число возможных проблем. Я бы рекомендовал не использовать это на протяжении всего кода, и вместо того, чтобы переместить его на classmethod на человека, как:

@classmethod 
def list_unaffiliated_people(cls): 
    return cls.objects.extra(where=['company_id IS NULL']) 

В качестве альтернативы, просто использовать правильный синтаксис ORM запросов и сосут хит возможной производительности (вы на самом деле протестированные более сложный запрос, чтобы увидеть, что это медленнее)

+0

Пробовал это в оболочке, это дает мне FieldError: Не удается разрешить ключевое слово 'company_id' в поле. Возможные варианты: компания, first_name, last_name – chefsmart

+0

Hrm. Я подумал, что можно запросить такой ключ. Наверное, он вернулся к чертежной доске. – Crast

+0

Это невозможно. 'company__id__isnull' будет действителен, но будет генерировать почти тот же SQL. – ayaz

0

Django будет относиться к NULL, как Пайтон None объекта так:

Person.objects.filter(company = None) 
+0

Это также дает тот же SQL. Я предполагаю, что Django делает это не так уж плохо в конце концов. Я сосредоточусь на том, как я могу улучшить свои другие поиски и посмотреть, смогу ли я решить свою проблему. – chefsmart

14

Ну, этот вопрос стар, и скоро патч будет в Django.Но для краткого Между тем, ответ в http://code.djangoproject.com/ticket/10790:

Workaround: Instead of

Person.objects.filter(company=None)

use

Person.objects.exclude(company__isnull=False)

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