2010-02-17 2 views
9

Lasst uns sagen, ich habe zwei Django Modelle Person und Gesellschaft wie folgt: -Django ForeignKey mit null = True, INNER JOIN und äußeren LEFT 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) 

Eine Person kann oder nicht zu einer Gesellschaft gehören.

Ich benutze MySQL. Ich möchte alle Personen, die keiner Gesellschaft angehören, dh Personen, bei denen die Gesellschaft null ist.

Wenn ich Person.objects.filter(company__isnull=True) erhalte ich eine SQL, die im wesentlichen: -

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

Wie gehe ich über das Erreichen der folgenden SQL: -

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

Von dem, was ich sammeln Beim Lesen der Django-Benutzer-Mailingliste war dies das Verhalten vor dem QuerySet-Refactor.

EDIT - Jetzt sehe ich die Blasphemie meiner Frage!

Was ich sagen will ist, ich einfach

SELECT * FROM PersonTable WHERE PersonTable.company_id IS NULL

+0

Nun, wenn dies nicht für Sie Sinn machen wird, das ist eigentlich eine ‚Basis‘ Abfrage, die inneren verbundenen mit anderen Abfragen erhält, und dies führt zu seltsamen , sich wiederholende Ergebnisse. – chefsmart

+0

Diese Frage ist wirklich ein Ergebnis einer mentalen Blockade. – chefsmart

Antwort

1

Es sollte so einfach sein wie zu tun:

Person.objects.filter(company_id__isnull=True) 

Beachten Sie die Verwendung von company_id, die die Standard-Integer-Feld ist erstellt durch die ForeignKey

bearbeiten

Sorry, ich habe Django seit 0.9.5 nicht mehr aktiv benutzt. Entweder denke ich an das Verhalten vor 1.0, oder ich mische sqlalchemy und Django ORM auf. In jedem Fall scheint das oben Genannte nicht zu funktionieren.

Es sieht so aus, als ob die einzige Möglichkeit, die gewünschte Abfrage im aktuellen Django zu erhalten, der Abfrageparameter .extra ist, der eine ganze Liste von Vorbehalten enthält.

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

Beachten Sie, dass dies nicht für alle DB tragbar sein kann, und es kann nicht mit filter(), und eine beliebige Anzahl von möglichen Problemen in Kombination arbeiten. Ich würde empfehlen, im gesamten Code nicht mit diesem, und statt es zu einer Class auf Person zu bewegen wie:

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

Alternativ verwenden Sie einfach die richtige ORM Abfragesyntax und saugt die möglichen Leistungseinbußen bis (haben Sie gebenchmarkt tatsächlich die kompliziertere Abfrage zu sehen, dass es ein langsamer ist)

+0

Versucht es in der Shell, es gibt mir FieldError: Kann das Schlüsselwort 'company_id' in Feld nicht auflösen. Die Auswahlmöglichkeiten sind: Firma, Vorname, Nachname – chefsmart

+0

Hrm. Ich dachte, dass es möglich ist, den Schlüssel so abzufragen. Ich denke, es ist zurück zum Zeichenbrett auf diesem. – Crast

+0

Das ist nicht möglich. 'company__id__isnull' wäre zwar gültig, würde aber nahezu das gleiche SQL generieren. – ayaz

0

Django None Objekt NULL als Python so behandeln:

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

Dies gibt auch die gleiche SQL. Ich schätze, die Art, wie Django es macht, ist gar nicht so schlimm. Ich werde mich darauf konzentrieren, wie ich meine anderen Lookups verbessern kann und ob ich mein Problem lösen kann. – chefsmart

14

Nun, diese Frage ist alt, und bald wird der Patch sein in Django.Aber für die kurze Zwischenzeit ist die Antwort in http://code.djangoproject.com/ticket/10790:

Workaround: Instead of

Person.objects.filter(company=None)

use

Person.objects.exclude(company__isnull=False)