2010-02-17 8 views
9

Diciamo che ho due modelli Django Persona e Società come segue: -Django ForeignKey con null = True, inner join, e ha lasciato outer join

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) 

una persona può o non può appartenere ad una società.

Sto usando MySQL. Voglio tutte le Persone che non appartengono a nessuna Azienda, cioè Persone in cui la società è nulla.

Se faccio Person.objects.filter(company__isnull=True) ottengo una SQL che è essenzialmente: -

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

Come posso fare per raggiungere il seguente SQL: -

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

Da quanto ho capito dalla lettura della mailing list di Django Users, questo era il comportamento prima di QuerySet Refactor.

EDIT - Ora vedo la bestemmia della mia domanda!

Quello che voglio dire è che semplicemente voglio fare

SELECT * FROM PersonTable WHERE PersonTable.company_id IS NULL

+0

Beh, se questo non è dare un senso a voi, questo è in realtà una query di 'base' che ottiene INTERNO è unito con altre query, e questo porta alla strana , risultati ripetitivi. – chefsmart

+0

Questa domanda è davvero il risultato di un blocco mentale. – chefsmart

risposta

1

Dovrebbe essere semplice come:

Person.objects.filter(company_id__isnull=True) 

Nota l'uso di company_id che è il campo default di un intero creato di ForeignKey

Modifica

Spiacente, non ho usato attivamente django dal 0.9.5. O sto pensando ad un comportamento pre-1.0, o sto confondendo sqlalchemy e Django ORM. In entrambi i casi, come indicato dai commenti, quanto sopra sembra non funzionare.

Sembra che l'unico modo per ottenere la query desiderata in corrente django sia utilizzare il parametro di query .extra, che viene fornito con un elenco completo di avvertimenti.

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

Si noti che questo potrebbe non essere portabile a tutti DB, e potrebbe non funzionare in combinazione con filtro(), e qualsiasi numero di possibili problemi. Raccomando di non utilizzare questo in tutto il codice, e invece lo spostamento in una classmethod sulla persona come:

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

In alternativa, basta usare la corretta sintassi di query ORM e aspirare il colpo prestazioni possibili (avete in realtà benchmark del interrogazione più complicato da vedere che è più lentamente)

+0

Provato nella shell, mi dà FieldError: Impossibile risolvere la parola chiave 'company_id' nel campo. Le scelte sono: azienda, first_name, last_name – chefsmart

+0

Hrm. Pensavo che fosse possibile interrogare la chiave in quel modo. Immagino che sia tornato al tavolo da disegno su quello. – Crast

+0

Questo non è possibile. 'company__id__isnull' sarebbe valido, ma genererebbe praticamente lo stesso SQL. – ayaz

0

Django tratterà NULL come Python None oggetto così:?

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

Questo dà anche lo stesso SQL. Immagino che il modo in cui Django lo sta facendo non sia poi così male. Mi concentrerò su come posso migliorare le mie altre ricerche e vedere se riesco a risolvere il mio problema. – chefsmart

14

Beh, questa domanda è vecchia, e presto la patch sarà in Django.Ma per il breve frattempo, la risposta è in http://code.djangoproject.com/ticket/10790:

Workaround: Instead of

Person.objects.filter(company=None)

use

Person.objects.exclude(company__isnull=False)