2009-08-23 17 views
12

Jest to prawdopodobnie obraźliwie proste i godne śmiechu Nelson Muntz, ale mam prawdziwy moment braindead próbując nawiązać wiele połączeń w różnych relacjach modelowych.Wiele do wielu wyszukiwań w Django

Mam następujące modele (uproszczony dla przyjemności!):

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 następujących użytkowników:

  • Alice ma 3 dokumenty, z których 1 jest prywatny (czyli tylko przyjaciół można zobaczyć ). Jest zaprzyjaźniona z Bobem, jest ignoruje Mallory i jest apatyczna w kierunku Eve (co oznacza, że ​​nie ma zapisanej relacji ).
  • Mallory ma 2 dokumenty, zarówno publiczne i jest apatyczny dla wszystkich.
  • Bob ma 1 dokument, który jest publicznie dostępny pod numerem i jest również apatyczny pod adresem dla wszystkich.
  • Ewa ignoruje Alice i apatyczny Mallory i Bob

użytkowników szukających dokumentów powinny produkować następujące:

  • Bob szukając dokumentów powinny zobaczyć 6, jak Alice uczynił go przyjaciel i może przeglądać jej prywatne dokumenty .
  • Alicja szukająca dokumentów powinna zobaczyć 4, Bobs 1 i jej 3. Ona nie jest zobacz publiczne dokumenty Mallory jako Alice ignoruje Mallory.
  • Mallory szukając dokumentów widzi 5 - te publiczne Alice, jej własne 2 i Bobs 1. Alicja ignorując jej nie ma wpływu na to, co Mallory widzi, tylko że Alice nie widzi Mallory'ego docs.
  • Ewa szuka dokumentów 3 - Dokumenty publiczne Mallory i Boba jako zignorowała Alice.

Zasadniczo mam mentalną walkę, zastanawiając się, czy filtry nie zwróciły zapytań, które opisałem powyżej. Czy ktoś ma jakieś pomysły?

EDIT

Dzięki Ferdinands odpowiedź poniżej udało mi się nakrętka przez co chciałem z początku, że dał mi. Po pierwsze, chcemy uzyskać listę ludzi, którzy friended mnie co jest wstecznego poprzez wiele do wielu relacji:

friendly_authors = self.user.user_friends.all() 

Get wszystkich ludzi mam ignorowane:

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

Pobierz listę docs mogę view - Dokumenty, które są widoczne, kopalnia, lub napisane przez ludzi, którzy friended mnie, ale którego nie zignorowali:

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

+1 dla jasnego opisu problemu :) –

Odpowiedz

8

jest to trochę skomplikowane, może szukasz czegoś takiego:

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

To generuje następujący kod SQL (zrobiłem jakieś formatowanie na oryginalnym wyjściu):

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

Dzięki za to, ty Dał mi dokładnie to, czego potrzebowałem, aby przełknąć to, co chciałem powrócić – Steerpike

Powiązane problemy