2012-10-12 13 views
6

Sono nuovo di Python e Django, quindi per favore sii paziente con me.Query complessa con Django (post di tutti gli amici)

Ho i seguenti modelli:

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'),) 

So che questo non può essere il/modo migliore più semplice per gestire con Django, ma ho imparato in questo modo e voglio continuare in questo modo.

Ora, tutto quello che voglio fare è ottenere tutto il post da una persona e dai suoi amici. La domanda ora è come farlo con i filtri Django?

penso in SQL sarebbe simile a questa:

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) 
) 

senza alcuna garanzia di correttezza, tanto per dare un'idea del risultato che sto cercando.

risposta

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

Siamo spiacenti, che era colpa mia. Non ho prestato attenzione ai tuoi valori related_name. Vedi il codice aggiornato sopra. L'utilizzo di userBy__accept_user o userBy__request_user da solo non funzionerà perché sarà un riferimento a Friend che non è possibile confrontare con User. Quello che stiamo facendo qui è seguire la relazione inversa a Friend e poi, una volta arrivati, verificare se l'utente altro sulla richiesta di amicizia è l'utente in questione.

Questo illustra anche l'importanza di descrivere le relazioni inverse in modo appropriato. Molte persone commettono lo stesso errore che hai fatto qui e nominano il related_name dopo il modello che stanno creando l'FK (User), quando in realtà, quando stiamo parlando di invertire l'FK, stiamo parlando di Friend. Semplicemente, i tuoi nomi correlati avrebbero più senso in qualcosa come: friend_requests e accepted_friends.

+0

c'è una chiave esterna dell'Utente che deve indicare Amici? – cesar09

+0

No. Il bit "__friend" segue la relazione all'indietro, poiché 'Friend' ha un FK per' Utente'. –

+0

Per ulteriori informazioni consultare la documentazione per [ricerche che abbracciano le relazioni] (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

L'approccio standard consiste nell'utilizzare l'oggetto 'Q'. Potresti chiarire _perché_ hai scelto un approccio diverso? – Tadeck

+0

Dove stai ottenendo "l'approccio standard è usare un oggetto Q"? Da nessuna parte nella documentazione dice questo. Inoltre, per un principiante di django, questo approccio scomposto può essere più facilmente comprensibile. – Colleen

+4

per esperienza. Stai prima raccogliendo tutti gli ID, quindi lo stai utilizzando per una query. Considera il caso in cui avresti 500 amici, la query potrebbe essere enorme. Sì, questa soluzione potrebbe essere utilizzata da Django newbie (o da qualcuno che conosce _why_ e _quando_ potrebbe essere migliore), ma non si tratta di ciò che è più facile da capire, piuttosto di ciò che è il migliore (o almeno "buono"). Per quanto riguarda la parte "standard approach": [leggi la documentazione su query complesse in Django] (https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q- oggetti). – Tadeck

Problemi correlati