2009-05-20 10 views
1

projet de classe (models.Model): utilisateurs = models.ManyToManyField (utilisateur, par 'Project_User' =)LEFT OUTER JOIN avec des définitions supplémentaires dans Django

class Project_User(models.Model): 
    project = models.ForeignKey('Project') 
    user = models.ForeignKey(User) 
    property = models.BooleanField() 

Tous les projets ont propres lignes de Project_User. Chose, ce dont j'ai besoin est d'obtenir un jeu de requêtes de tous les projets où le champ "propriété" de l'utilisateur courant! = True ou la ligne Project_User de l'utilisateur actuel n'existe pas. Est-ce qu'il y a un moyen de le faire en utilisant l'ORM de django? Comme résultat, j'ai besoin de l'objet Queryset pour lui appliquer d'autres filtres. En utilisant SQL personnalisé, je peux le faire. utilisateur actuel ont id == XXXX:

SELECT * FROM "app_project" LEFT OUTER JOIN "app_project_user" 
ON ("app_project"."id" = "app_project_user"."project_id" 
    AND ("app_project_user"."user_id" = XXXX OR "app_project_user"."user_id" IS NULL)) 
WHERE ("app_project_user"."property" = false OR "app_project_user"."property" IS NULL); 

je l'espère, il est possible, mais je ne sais pas comment, mais ..

Merci pour toute aide!

Répondre

0

Quelque chose le long des lignes de

p = Projects.objects.filter(users=current_user) 
p = p.exclude(project_user__user=current_user, 
       project_user__property=True) 

Cela devrait vous donner une queryset de tous les projets pour l'utilisateur actuel, l'exclusion de ceux pour lesquels il y a un Project_User pour l'utilisateur actuel qui est la valeur de la propriété est vrai

plus d'informations: http://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships

+0

Ce n'est pas bon pour moi, car ORM génère des sous-requêtes. Et ça ne marche pas, quand j'ai plusieurs champs booléens - une sous-requête pour un champ. – ramusus

3

Pour les recherches complexes (et toute recherche, impliquant essentiellement OU), je recommande Django's Q operator.

Dans ce cas, la requête pourrait ressembler à:

from django.db.models import Q 

q = (Q(project_user=my_current_user) | Q(project_user=None)) & \ 
    (Q(project_user__property=False) | Q(project_user__property=None)) 
projects = Project.objects.filter(q) 

Dans ce cas, ne pas oublier d'indiquer que NULL est autorisé pour votre champ property:

class Project_User(models.Model): 
    # ... as above, then: 
    property= models.BooleanField(null=True) 

Sinon, django émettra CREATE TABLE sql pour le champ property qui indique spécifiquement que null n'est pas autorisé ("property" bool NOT NULL), ce qui serait en contradiction avec l'utilisation de Q(project_user__property=None).

+0

merci, il est devenu plus clair pour moi. Un problème, que je vois: Project.objects.filter (Q (project_user = my_current_user) | Q (project_user = None)). se transforme en SELECT COUNT (*) FROM "app_project" LEFT OUTER JOIN "app_project_user" ON ("app_project". "Id" = "app_project_user". "Project_id") LEFT OUTER JOIN "auth_user" ON ("app_project_user" . "user_id" = "auth_user". "id") WHERE ("app_project_user". "user_id" = 10 OU "auth_user". "id" EST NUL). Je ne comprends pas ce que le second LEFT OUTER JOIN avec la table auth_user. Il retourne un autre résultat, puis avec 1 jointure. Y a-t-il un moyen de l'éviter? – ramusus

+0

La meilleure solution pour moi génère cette requête: SELECT COUNT (*) FROM "app_project" LEFT OUTER JOIN "utilisateur_applicateur_app" ON ("app_project". "Id" = "utilisateur_projet_application". "ID_projet" AND "utilisateur_projet_application". " user_id "= 10 OU" app_project_user "." user_id "EST NULL) Mais je ne sais pas Est-ce possible avec la clause Q (project_user = None). – ramusus

+0

La deuxième jointure avec auth_user est probable parce que vous utilisez (correctement) request.user pour déterminer l'utilisateur actuel. request.user est une instance de django.auth.models.User, d'où la jointure à la table auth_user. Je ne m'inquiéterais pas de baby-sitting chaque SQL généré individuellement. Construisez votre application, et si la performance n'est pas ce que vous espérez, optimisez. –

Questions connexes