2009-08-23 12 views
12

Esto es probablemente insultantemente simple y digno de una risa de Nelson Muntz, pero estoy teniendo un momento de muerte cerebral real tratando de hacer muchas conexiones a través de varias relaciones modelo.Muchas o muchas búsquedas en Django

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

  • Alice tiene 3 documentos, 1 de los cuales es privada (es decir, sólo amigos puede ver ). Ella es amiga de Bob, está haciendo caso omiso de Mallory y es apática hacia Eva (es decir, sin relación almacenada ).
  • Mallory tiene 2 documentos, ambos públicos y es apático para todos.
  • Bob tiene 1 documento que es público y también es apático hacia todos.
  • Eva está ignorando Alice y es apáticos a Mallory y Bob

usuarios que buscan documentos debe producir lo siguiente:

  • Bob búsqueda de documentos deben véase 6, como Alice lo ha hecho un amigo y él puede ver sus documentos privados .
  • Alicia buscando documentos debe ver 4, Bobs 1 y su 3. Ella no ver los documentos públicos de Mallory como Alicia está ignorando a Mallory.
  • Mallory búsqueda de documentos ve 5 - las públicas de Alice, su propia 2 y Bobs 1. Alice ignorando su no tiene ninguna relación con lo que Mallory se puede ver, apenas que Alice no ve documentos de Mallory.
  • Eve buscando documentos ve 3 - documentos públicos de Mallory y Bob como ella ha ignorado a Alice.

Básicamente, tengo una lucha mental para descifrar los filtros para devolver los querysets que describí anteriormente. ¿Alguien tiene alguna idea?

EDITAR

Gracias a la respuesta Ferdinands continuación pude a la tuerca a través de lo que quería con el principio que él me dio. En primer lugar, queremos obtener una lista de 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() 

consiguen a 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 la que no han pasado por alto:

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

+1 para la descripción clara del problema :) –

Respuesta

8

es un poco complicado, tal vez están 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 código SQL (he 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 
     ) 
    ) 
) 
+0

Gracias por eso, me dio exactamente lo que necesitaba para tuerca a través de lo que quería devolver – Steerpike

Cuestiones relacionadas