2015-10-04 16 views
6

Ich habe ein Modell wie sodjango 1.7 linke äußere Verknüpfung

class Job(models.Model): 
    description = models.CharField(max_length=255) 
    user = models.ForeignKey(User) 
    date = models.DateField() 
    slot = models.CharField(max_length=10, choices=SLOT_CHOICES) 
    location = models.ForeignKey(Location)   
    objects = JobManager() 
    searches = geomodels.GeoManager() 

    class Meta: 
     verbose_name_plural = "Job" 
     unique_together = ('date', 'slot', 'user') 

    def __str__(self): 
     return "{0}-{1}".format(self.user.first_name, self.date) 

class Applied(models.Model): 
    user = models.ForeignKey(User) 
    job = models.ForeignKey(Job, null=True, blank=True) 
    action_taken = models.BooleanField(default=False) 
    is_declined = models.BooleanField(default=False) 

    class Meta: 
     verbose_name_plural = "Job Applications" 
     unique_together = ('user', 'job',) 

Ich möchte für alle Arbeitsplätze zwischen einem Datumsbereich suchen und zeigen, ob ein Benutzer anwenden können, bereits angewendet oder abgelehnt wurde. Die Anwendungsinformationen sind im angewandten Modell.

Aber ich kann es nicht funktionieren, es ist nicht eine linke Join auf der angewandten Tabelle in der Datenbank. irgendwelche Vorschläge, wie es funktioniert.

Dank

+0

Vergib mir zu fragen, aber Wäre eine innere Verbindung nicht ausreichend? – e4c5

+0

Innerer Join bringt nur die Zeilen, die in beiden Tabellen vorhanden sind, ich möchte einen ausgelassenen Join, wie ich alle Zeilen aus der Jobtabelle zwischen dem Datumsbereich und Zeilen aus der angewendeten Tabelle möchte, wenn der Benutzer bereits für diesen Job beantragt hat und wenn es gewesen ist abgelehnt. –

+1

Ihr Code sollte Ihnen das richtige Ergebnis geben (gefilterte Jobs mit einem applied_set, das möglicherweise leer ist), obwohl keine Joins vorhanden sind. "prefetch_related wird in den meisten Fällen mit einer SQL-Abfrage implementiert, die den 'IN'-Operator verwendet." https://docs.djangoproject.com/en/1.7/ref/models/querysets/#prefetch-related – JimmyYe

Antwort

4

Django ORM führen LEFT OUTER JOIN wenn FK des NULLABLE sind.

Lösung: nur hinzufügen null=True auf dieser FK job = models.ForeignKey(Job, null=True, blank=True) Sie wollen immer nulls beitreten und Django INNER von LEFT OUTER JOIN ändern JOIN.

Dies ist logisch, da linker äußerer Join sinnvoll ist, wenn die Zieltabellen möglicherweise keine exakte Übereinstimmung haben, die die meist linke Tabelle in der Abfrage dominiert.

UPDATE: Dies funktioniert nur für ForeignKey Feld und select_related, nicht für ManyToMany Felder mit prefetch_related.

Mögliche Lösung für M2M-Felder:

  1. Debug die SQL generiert (DEBUG = True, mit Logger 'django.db.backends' Logging)
  2. es Kopieren und ersetzen INNER JOIN mit LEFT OUTER JOIN
  3. Perform Model.objects.raw (sql_with_left_join)

https://docs.djangoproject.com/en/1.8/topics/db/sql/#performing-raw-sql-queries

Dies sollte die gleichen Ergebnisse wie zuvor geben, aber die Jobs hinzufügen, die M2M nicht mit Applied haben.

UPDATE2: Benutzerdefinierte in Django JOINS für Versionen < = 1,5, nicht auf die Arbeit 1.6+

in diesem Blog-Eintrag gefunden: https://www.caktusgroup.com/blog/2009/09/28/custom-joins-with-djangos-queryjoin/

Von Stackoverflow: https://stackoverflow.com/a/12943120/1090700

+0

Prost, das macht Sinn. Will es versuchen. –

+0

Ich habe das Modell gemäß Ihrem Vorschlag aktualisiert, funktioniert aber immer noch nicht. Ich bekomme keine Referenz auf die angewendete Tabelle in der Abfrage. –

+0

Dies ist wahrscheinlich auf ManyToMany zurückzuführen, was ich sagte, war für select_related und ForeignKey, nach dem Testen, überprüft, dass in M2M tut es nicht. Sie müssten wahrscheinlich einen Job.objects.raw erstellen, wenn Sie M2M mit einem LEFT OUTER JOIN überspringen möchten (debuggen Sie einfach das generierte SQL und ersetzen Sie INNER JOIN durch LEFT OUTER JOIN): https://docs.djangoproject.com/de /1.8/topics/db/sql/#performing-raw-sql-abfragen – danigosa