Django ForeignKey с null = True, внутренним соединением и левым внешним соединением - PullRequest
9 голосов
/ 17 февраля 2010

Допустим, у меня есть две модели Django Person и Company следующим образом: -

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.

РЕДАКТИРОВАТЬ - Теперь я вижу богохульство моего вопроса!

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

SELECT * FROM PersonTable WHERE PersonTable.company_id IS NULL

Ответы [ 3 ]

14 голосов
/ 23 апреля 2011

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

Обход проблемы: вместо

Person.objects.filter(company=None)

используйте

Person.objects.exclude(company__isnull=False)

1 голос
/ 17 февраля 2010

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

Person.objects.filter(company_id__isnull=True)

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

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

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

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

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

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

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

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

0 голосов
/ 17 февраля 2010

Django будет воспринимать NULL как объект None Python, поэтому:

Person.objects.filter(company = None)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...