Frage

Dies ist wahrscheinlich insultingly einfach und würdig ein Nelson Muntz lachen, aber ich bin einen echten hirntot Moment mit tryng machen viele, viele Verbindungen über verschiedene Modellbeziehungen.

Ich habe folgende Modelle (vereinfacht zum nachmachen!):

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 die folgenden Benutzer:

  • Alice hat drei Dokumente, 1 davon privat (was bedeutet, nur Freunde sehen es). Sie ist befreundet mit Bob, ist Ignorieren Mallory und apathisch ist nicht gespeichert zu Eve (im Sinne von Beziehung).
  • Mallory hat zwei Dokumente, sowohl öffentliche und ist apathisch gegenüber jedermann.
  • Bob hat 1 Dokument, das öffentlich ist und ist auch apathisch gegen jeden etwas dabei.
  • Eve ignoriert Alice und ist apathisch zu Mallory und Bob

Benutzer der Suche nach Dokumenten sollten produzieren die folgenden:

  • Bob der Suche nach Dokumenten sollte siehe 6, als Alice ihn gemacht hat, einen Freund und er kann sie Privat ansehen Dokumente.
  • Alice Suche nach Dokumenten sollte siehe 4, Bob 1 und ihre 3. Das tut sie nicht siehe Mallorys öffentliche Dokumente als Alice ignoriert Mallory.
  • Mallory Suche nach Dokumenten sieht 5 - Alices öffentlich diejenigen, ihr eigenen 2 und Bobs 1. Alice ignorierte sie hat keine Lager auf, was Mallory sehen kann, nur dass Alice nicht sieht Mallory docs.
  • Eve Suche nach Dokumenten sieht 3 - Mallory und Bob öffentliche Dokumente wie sie Alice hat ignoriert.

Grundsätzlich ist ich einen mentalen Kampf mit den Filter herauszufinden, um die querysets Rückkehr ich oben beschrieben. Jemand irgendwelche Ideen?

Bearbeiten

Dank Ferdinands Antwort unten konnte ich auf die Mutter durch das, was ich mit dem Start wollte, dass er mir gab. Zunächst einmal wollen wir eine Liste von Leuten bekommen, die mir friended haben, welche ein Reverse-Lookup durch die viele zu viele Beziehung ist:

friendly_authors = self.user.user_friends.all()

Erfahren Sie alle Leute, die ich ignoriert habe:

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

eine Liste der Dokumente erhält ich sehen kann - docs, die sichtbar sind, mine, oder von Menschen, die mir friended haben, aber den ich nicht außer Acht gelassen:

docs = Document.objects.filter(
    (Q(viewable=True) | Q(author=self.user) | Q(author__in=friendly_authors))
     & ~Q(author__in=my_ignored)
)
War es hilfreich?

Lösung

Es ist ein bisschen schwierig, vielleicht suchen Sie etwas wie folgt aus:

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

Dies erzeugt die folgende SQL (I auf der ursprünglichen Ausgabe einige Formatierungen tat):

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
        )
    )
)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top