2012-04-03 23 views
6

Tengo problemas para que una consulta ORM de Django funcione correctamente. Tengo este modelo Amistad:Consulta ORM de Django para amigos de un usuario

class Friendship(models.Model): 
    user1 = models.ForeignKey(User, related_name='friendships1') 
    user2 = models.ForeignKey(User, related_name='friendships2') 
    class Meta: 
     unique_together = ('user1', 'user2',) 

localización de amigos de un usuario determinado, tenemos que comprobar usuario1 y usuario2 porque nunca podemos estar seguros de qué lado de la relación que estarán encendidas. Por lo tanto, para obtener todos los amigos de un usuario determinado, utilizo la siguiente consulta:

user = request.user 
User.objects.filter(
    Q(friendships1__user2=user, friendships1__status__in=statuses) | 
    Q(friendships2__user1=user, friendships2__status__in=statuses) 
) 

Esto me parece que debería funcionar, pero no es así. Me da duplicados. Aquí está el SQL que se genera:

SELECT auth_user.* 
FROM auth_user 
LEFT OUTER JOIN profile_friendship ON (auth_user.id = profile_friendship.user1_id) 
LEFT OUTER JOIN profile_friendship T4 ON (auth_user.id = T4.user2_id) 
WHERE (
    (profile_friendship.status IN ('Accepted') AND profile_friendship.user2_id = 1) 
    OR (T4.user1_id = 1 AND T4.status IN ('Accepted')) 
); 

aquí es el SQL que quiero, lo que produce resultados correctos:

SELECT f1.id as f1id, f2.id AS f2id, u.* 
FROM auth_user u 
LEFT OUTER JOIN profile_friendship f1 ON (u.id = f1.user1_id AND f1.user2_id = 1 AND f1.status IN ('Accepted')) 
LEFT OUTER JOIN profile_friendship f2 ON (u.id = f2.user2_id AND f2.user1_id = 1 AND f2.status IN ('Accepted')) 
WHERE f1.id IS NOT NULL OR f2.id IS NOT NULL 

Sé que puedo hacer esto en una consulta en bruto, pero entonces don No creo que pueda encadenar. ¿Hay una buena y limpia forma de hacerlo sin ir en bruto?

Respuesta

1

solución simple:

user = request.user 
User.objects.filter(
    Q(friendships1__user2=user, friendships1__status__in=statuses) | 
    Q(friendships2__user1=user, friendships2__status__in=statuses) 
).distinct() 

Alguien sabe cualquier inconveniente?

+0

He probado esto y funciona. Personalmente, no escribiría la consulta exactamente como lo está escupiendo el ORM, pero aún parece funcionar razonablemente bien. El único inconveniente aquí es los posibles duplicados al usar un campo en orden por el que no está incluido en el conjunto de resultados. – Dustin

3
+0

Necesita almacenar información adicional, parece que no funcionará. – santiagobasulto

+0

@santiagobasulto o especifique un [a través de la tabla] (https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany) para el M2M –

+0

La solución de la solución @santiagobasulto me funciona. Sin embargo, me pregunto si esta solución podría ser un poco más simple y tal vez incluso funcione mejor, siempre y cuando aún pueda especificar una tabla directa. Sin embargo, no tengo claro cómo hacer eso en una relación simétrica. Estoy tratando de resolver eso ahora ... – Dustin

Cuestiones relacionadas