2009-12-23 16 views
7

sagen, ich habe die folgenden Modelle:Django Allgemeine Relations und ORM Abfragen

class Image(models.Model): 
    image = models.ImageField(max_length=200, upload_to=file_home) 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey() 

class Article(models.Model): 
    text = models.TextField() 
    images = generic.GenericRelation(Image) 

class BlogPost(models.Model): 
    text = models.TextField() 
    images = generic.GenericRelation(Image) 

Was ist die Prozessor- und Speicher-effiziente Art und Weise alle Artikel zu finden, die mindestens ein Bild mit ihnen verbunden haben?

Ich habe dies getan:

Article.objects.filter(pk__in=Image.objects.filter(content_type=ContentType.objects.get_for_model(Article)).values_list('object_id', flat=True)) 

Welche funktioniert, aber neben hässlich es dauert ewig.

Ich vermute, es gibt eine bessere Lösung mit Raw SQL, aber das ist jenseits meiner. Für das, was es wert ist, erzeugt die SQL durch das oben ist wie folgt:

SELECT `issues_article`.`id`, `issues_article`.`text` FROM `issues_article` WHERE `issues_article`.`id` IN (SELECT U0.`object_id` FROM `uploads_image` U0 WHERE U0.`content_type_id` = 26) LIMIT 21 

EDIT: czarchaic Vorschlag viel schöner Syntax hat aber noch schlimmer (langsamer) Leistung. Die SQL erzeugt durch seine Abfrage sieht wie folgt aus:

SELECT DISTINCT `issues_article`.`id`, `issues_article`.`text`, COUNT(`uploads_image`.`id`) AS `num_images` FROM `issues_article` LEFT OUTER JOIN `uploads_image` ON (`issues_article`.`id` = `uploads_image`.`object_id`) GROUP BY `issues_article`.`id` HAVING COUNT(`uploads_image`.`id`) > 0 ORDER BY NULL LIMIT 21 

EDIT: Hooray für Jarret Hardie! Hier ist die SQL durch seine erzeugte sollte-Have-been-offensichtliche Lösung:

SELECT DISTINCT `issues_article`.`id`, `issues_article`.`text` FROM `issues_article` INNER JOIN `uploads_image` ON (`issues_article`.`id` = `uploads_image`.`object_id`) WHERE (`uploads_image`.`id` IS NOT NULL AND `uploads_image`.`content_type_id` = 26) LIMIT 21 
+0

Ist das Ihre tatsächliche Modellstruktur, oder gibt es eine ganze Klassenhierarchie, die Sie nicht die Einfachheit halber in Frage Beispiel repräsentieren? Ich frage, weil dieses spezielle Beispiel keine Generika benötigt. –

+0

Nein, das ist eine abgespeckte und vereinfachte Modellstruktur. – hanksims

+1

Obwohl Ihre angenommene Antwort recht gut funktioniert, bin ich neugierig zu wissen, was die Lösung wäre, wenn Sie etwas anderes als "mindestens ein Bild" benötigen würden. – czarchaic

Antwort

6

Dank generische Beziehungen zu verwenden wäre, sollten Sie in der Lage sein abfragen diese Struktur mit traditioneller Abfrage-set Semantik für Reverse-Beziehungen:

Article.objects.filter(images__isnull=False) 

Dies wird Duplikate für all Article s erzeugen, die auf mehrverbunden sinds, aber Sie können das mit der distinct() QuerySet Methode beseitigen:

Article.objects.distinct().filter(images__isnull=False) 
+0

Ich denke, wir haben einen Gewinner! Ich werde das generierte SQL in einer anderen Bearbeitung nur der Vollständigkeit wegen posten. Ran Beleuchtung-schnell, obwohl. is_null = False ... manchmal starren dich die einfachsten Dinge direkt ins Gesicht. – hanksims

+0

Danke hanksims ... hoffe es klappt :-) Ich gebe zu, ich habe mir das SQL nicht angeschaut, also definitiv neugierig das zu sehen. –

1

Ich denke, Ihre beste Wette aggregation

from django.db.models import Count 

Article.objects.annotate(num_images=Count('images')).filter(num_images__gt=0) 
+0

Macht Sinn, läuft aber langsamer! Siehe die Änderung. – hanksims