Pregunta

Este es probablemente insultantemente sencillo y digno de una risa Nelson Muntz, pero estoy teniendo un verdadero momento braindead tryng hacer muchos a muchos conexiones a través de diversas relaciones de modelos.

Tengo los siguientes modelos (simplificado para su disfrute!):

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 los usuarios siguientes:

  • Alice tiene 3 documentos, de los cuales 1 es privadas (lo que significa que solo amigos pueden ver eso). Ella es amiga de Bob, es haciendo caso omiso de Mallory y es apática hacia Eve (sin significado almacenado relación).
  • Mallory tiene 2 documentos, tanto públicos y es apática hacia todos.
  • Bob tiene 1 documento que es pública y también es apática hacia todo el mundo.
  • Eva está ignorando Alice y es apáticos a Mallory y Bob

Los usuarios que buscan documentos deben producir lo siguiente:

  • Bob búsqueda de documentos debe véase 6, ya que Alice le ha hecho un amigo y él puede ver su privado documentos.
  • Alice búsqueda de documentos debe ver 4, Bobs 1 y la 3. Ella no lo hace véanse los documentos públicos como de Mallory Alice está haciendo caso omiso de Mallory.
  • Mallory ve la búsqueda de documentos 5 - las públicas de Alice, su propia 2 y Bobs 1. Alice ignorándola no tiene teniendo en Mallory lo puede ver, apenas que Alice no ve Mallory docs.
  • Eva búsqueda de documentos ve 3 - Mallory y documentos públicos de Bob como ella ha ignorado Alice.

Básicamente, estoy teniendo una lucha mental averiguar los filtros para devolver los QuerySets he descrito anteriormente. ¿Alguien tiene alguna idea?

Editar

Gracias a Ferdinands respuesta a continuación pude NUT a través de lo que quería con el principio que él me dio. En primer lugar, queremos obtener una lista de las personas que me han friended que es una búsqueda inversa a través de la relación muchos a muchos:

friendly_authors = self.user.user_friends.all()

Obtener todas las personas que han ignorado:

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

Obtener una lista de documentos que puedo ver - documentos que son visibles, la mía, o escritos por personas que me han friended pero a quien no he ignorado:

docs = Document.objects.filter(
    (Q(viewable=True) | Q(author=self.user) | Q(author__in=friendly_authors))
     & ~Q(author__in=my_ignored)
)
¿Fue útil?

Solución

Es un poco complicado, tal vez usted está buscando algo así:

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

Esto genera el siguiente SQL (I hecho un poco de formato en la salida original):

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
        )
    )
)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top