2009-08-23 14 views
12

Questo è probabilmente insultantemente semplice e degno di una risata di Nelson Muntz, ma sto avendo un vero e proprio momento di coraggio per creare molte e molte connessioni attraverso varie relazioni tra modelli.Molte a molte ricerche in Django

ho i seguenti modelli (semplificato per il vostro divertimento!):

class Document(models.Model): 
    title = models.CharField(max_length=200) 
    author = models.ForeignKey(User, blank=True) 
    content = models.TextField(blank=True) 
    private = models.BooleanField(default=False) 

class UserProfile(models.Model): 
    user = models.ForeignKey(User, unique=True) 
    friends = models.ManyToManyField(User, symmetrical=False, 
            related_name='user_friends') 
    ignored = models.ManyToManyField(User, symmetrical=False, 
            related_name='user_ignored') 

Imaginging i seguenti utenti:

  • Alice dispone di 3 documenti, di cui 1 privato (che significa solo amici può vedere it). È amica di Bob, è ignorando Mallory ed è apatica verso Eve (che significa non memorizzata la relazione ).
  • Mallory ha 2 documenti, entrambi pubblici ed è apatico nei confronti di tutti.
  • Bob ha 1 documento che è pubblico ed è anche apatico verso tutti.
  • Eva sta ignorando Alice ed è apatico a Mallory e Bob

utenti alla ricerca di documenti dovrebbe produrre il seguente:

  • Bob ricerca di documenti dovrebbero vedere 6, come Alice lo ha fatto un amico e può visualizzare i suoi documenti privati ​​ .
  • Alice alla ricerca di documenti dovrebbe vedere 4, Bobs 1 e lei 3. Lei non vedere documenti pubblici di Mallory come Alice sta ignorando Mallory.
  • Mallory ricerca di documenti vede 5 - quelli pubblica di Alice, il suo 2 e Bobs 1. Alice ignorando la sua non ha alcuna attinenza con ciò che Mallory può vedere, solo che Alice non vede documenti di Mallory.
  • Eve cerca documenti vede 3 - documenti pubblici di Mallory e Bob come ha ignorato Alice.

Fondamentalmente, sto avendo una lotta mentale a capire i filtri per restituire i set di query che ho descritto sopra. Qualcuno ha qualche idea?

EDIT

Grazie a Ferdinands risposta qui sotto ho potuto Nut attraverso quello che volevo con l'inizio che mi ha dato. Prima di tutto, vogliamo ottenere un elenco di persone che mi hanno friended che è una ricerca inversa attraverso la relazione molti a molti:

friendly_authors = self.user.user_friends.all() 

ottenere tutti le persone che ho ignoravo:

my_ignored = UserProfile.objects.get(user=self.user).ignored.all() 

ottenere un elenco di documenti che possono visualizzare documenti - che sono visualizzabili, il mio, o scritta da persone che mi hanno friended ma che non ho ignorato:

docs = Document.objects.filter(
    (Q(viewable=True) | Q(author=self.user) | Q(author__in=friendly_authors)) 
    & ~Q(author__in=my_ignored) 
) 
+0

+1 per una chiara descrizione del problema :) –

risposta

8

e 'un po' complicato, forse si sono alla ricerca di qualcosa di simile:

>>> from django.db.models import Q 
>>> me = User.objects.get(pk=1) 
>>> my_friends = UserProfile.objects.get(user=me).friends.all() 
>>> docs = Document.objects.filter(
...  Q(author=me) | (
...   Q(author__in=my_friends) 
...   & ~Q(author__userprofile__ignored=me) 
... ) 
...) 

Questo genera il seguente SQL (ho fatto un po 'di formattazione in uscita originale):

SELECT "myapp_document".* 
FROM "myapp_document" WHERE (
    "myapp_document"."author_id" = %s 
    OR (
     "myapp_document"."author_id" IN (
      SELECT U0."id" FROM "myapp_user" U0 
      INNER JOIN "myapp_userprofile_friends" U1 
       ON (U0."id" = U1."user_id") 
      WHERE U1."userprofile_id" = %s 
     ) 
     AND NOT (
      "myapp_document"."author_id" IN (
       SELECT U2."user_id" FROM "myapp_userprofile" U2 
       INNER JOIN "myapp_userprofile_ignored" U3 
        ON (U2."id" = U3."userprofile_id") 
       WHERE U3."user_id" = %s 
      ) 
      AND "myapp_document"."author_id" IS NOT NULL 
     ) 
    ) 
) 
+0

Grazie per questo, mi ha dato esattamente quello di cui avevo bisogno per superare quello che volevo tornare – Steerpike

Problemi correlati