2012-10-12 6 views
6

Ich bin neu bei Python und Django, also bitte gedulden Sie sich mit mir.Komplexe Abfrage mit Django (Posts von allen Freunden)

Ich habe folgende Modelle:

class User(models.Model): 
    name = models.CharField(max_length = 50) 
    ... 

class Post(models.Model): 
    userBy = models.ForeignKey(User, related_name='post_user') 
    userWall = models.ForeignKey(User, related_name='receive_user') 
    timestamp = models.DateTimeField() 
    post = models.TextField() 

class Friend(models.Model): 
    user1 = models.ForeignKey(User, related_name='request_user') 
    user2 = models.ForeignKey(User, related_name='accept_user') 
    isApproved = models.BooleanField() 
    class Meta: 
     unique_together = (('user1', 'user2'),) 

Ich weiß, dass dies nicht der beste/einfachste Weg sein, kann es mit Django zu handhaben, aber ich lernte es auf diese Weise, und ich mag es halten wie diese.

Nun, alles, was ich tun möchte, ist bekommen alle Post von einer Person und es ist Freunde. Die Frage ist jetzt, wie man es mit den Django-Filtern macht?

Ich denke, in SQL es in etwa so aussehen würde:

SELECT p.* FORM Post p, Friend f 
WHERE p.userBy=THEUSER OR (
    (f.user1=THEUSER AND f.user2=p.userBy) OR 
    (f.user2=THEUSER AND f.user1=p.userBy) 
) 

nur ohne Garantie auf Richtigkeit, eine Vorstellung des Ergebnisses zu geben, die ich suche.

Antwort

8
from django.db.models import Q 

Post.objects.filter(\ 
    Q(userBy=some_user) | \ 
    Q(userBy__accept_user__user1=some_user) | \ 
    Q(userBy__request_user__user2=some_user)).distinct() 

UPDATE

Sorry, das war meine Schuld. Ich habe Ihre related_name Werte nicht beachtet. Siehe aktualisierten Code oben. Die Verwendung von userBy__accept_user oder userBy__request_user alleine funktioniert nicht, da dies eine Referenz auf Friend ist, die Sie nicht mit User vergleichen können. Was wir hier machen, ist die umgekehrte Beziehung zu Friend und dann, wenn wir dort sind, sehen, ob der andere Benutzer auf der Freundschaftsanfrage der betreffende Benutzer ist.

Dies zeigt auch die Bedeutung der Beschreibung von umgekehrten Beziehungen in geeigneter Weise. Viele Leute machen denselben Fehler, den Sie hier gemacht haben, und benennen den related_name nach dem Modell, zu dem sie den FK erstellen (User), wenn wir gerade über die Umkehrung des FK sprechen, sprechen wir jetzt über Friend. Einfach ausgedrückt, Ihre verwandten Namen würden mehr Sinn als etwas wie: friend_requests und accepted_friends.

+0

Gibt es einen Fremdschlüssel vom Benutzer, der auf Freunde zeigen muss? – cesar09

+0

Nein. Das Bit "__friend" folgt der Beziehung rückwärts, da "Friend" einen FK zu "User" hat. –

+0

Weitere Informationen finden Sie in der Dokumentation zu [Suchen, die Beziehungen überspannen] (https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships). –

0
(with User u) 
friends_u1 = Friend.objects.filter(user1 = u).getlist('user2_id', flat=True) 
friends_u2 = Friend.objects.filter(user2 = u).getlist('user1_id', flat=True) 
friends_and_user = friends_u1+friends_u2+u.id 

Post.objects.filter(userBy__id__in = friends_and_user) 
+0

Der Standardansatz ist die Verwendung von 'Q'-Objekt. Könnten Sie erklären, warum Sie einen anderen Ansatz gewählt haben? – Tadeck

+0

Wo bekommen Sie "der Standardansatz ist ein Q-Objekt zu verwenden"? Nirgendwo in der Dokumentation heißt das. Auch für einen Django-Neuling kann dieser ausgebrochene Ansatz leichter verständlich sein. – Colleen

+4

Aus Erfahrung. Sie sammeln zuerst alle IDs und verwenden sie dann für eine Abfrage. Betrachten Sie den Fall, wo Sie 500 Freunde haben würden, könnte die Abfrage enorm sein. Ja, diese Lösung könnte von Django-Neulingen verwendet werden (oder von jemandem, der weiß, warum und wann es besser sein könnte), aber es geht nicht darum, was leichter zu verstehen ist, sondern was am besten (oder zumindest "gut") ist. Wenn es um den "Standardansatz" geht: [Lesen Sie die Dokumentation zu komplexen Anfragen in Django] (https://docs.djangoproject.com/de/dev/topics/db/queries/#complex-lookups-with-q- Objekte). – Tadeck