2010-07-25 4 views
6

Est-il possible d'ajouter une condition supplémentaire à la jointure créée par django ORM?conditions supplémentaires lors de la jointure dans django

Ce que j'ai besoin dans SQL est

'SELECT "post"."id", COUNT("watchlist"."id") FROM "post" 
LEFT OUTER JOIN "watchlist" 
    ON ("post"."id" = "watchlist"."post_id" AND "watchlist"."user_id" = 1) 
WHERE "post"."id" = 123 GROUP BY … 

En django plus cela est

Post.objects.annotate(Count('watchinglist')).get(pk=123) 

Mais comment puis-je ajouter AND "watchlist"."user_id" = … en condition join avec django ORM? L'ajout au filtre n'obtient pas d'objets Post sans objets associés dans la liste de surveillance.

Répondre

0
Post.objects.annotate(Count('watchinglist')).filter(pk=123).extra(where=['"watchlist"."user_id" = 1']) 

Codage heureux.

+2

On dirait qu'il fait acually la même chose que le filtre(). Par exemple. ajouter un paramètre à WHERE, pas à ON, et donc fournir un résultat vide s'il n'y a pas d'objet watchlist. – HoverHell

+0

Mais, en fait, bonne idée. J'ai manqué le paramètre 'supplémentaire' de Count. On dirait que ça marche. – HoverHell

+0

... ou peut-être pas. "extra" il semble y avoir un but un peu différent. – HoverHell

2

Réponse courte: dans certaines conditions - oui. Lorsque la construction LEFT JOINs avec GenericForeignKey, Django appelle GenericRelation.get_extra_restriction qui ajoute une condition supplémentaire à la clause ON avec la restriction "content_type_id".

Pour "ForeignKey", cette méthode est également appelée par les retours None.

Vous pouvez utiliser cet emplacement pour ajouter des restrictions dans la clause ON, si vous parvenez à organiser votre code pour obtenir des paramètres de restriction appropriés à un certain moment.

class UserForeignKey(models.ForeignKey): 

    def get_extra_restriction(self, where_class, alias, related_alias): 
     field = self.model._meta.get_field('user') 
     cond = where_class() 
     # Here is a hack to get custom condition parameters 
     value = SomeContextManager.get_needed_value() 

     lookup = field.get_lookup('exact')(field.get_col(related_alias), value) 
     cond.add(lookup, 'AND') 
     return cond 

class WatchList(models.Model): 

    user = UserForeignKey(User) 
+0

Vous avez sauvé ma vie l'homme :) –

0

Dans Django v2.0 utilisation FilteredRelation

Post.objects.annotate(
    t=FilteredRelation(
     'watchlist', condition=Q(watchlist__user_id=1) 
).filter(t__field__in=...) 
Questions connexes