2010-07-25 27 views
6

E 'possibile aggiungere una condizione aggiuntiva all'istruzione join creata da django ORM?condizioni aggiuntive su join in django

Che cosa ho bisogno in SQL è

'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 … 

In django la maggior parte di questo è

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

ma come posso aggiungere AND "watchlist"."user_id" = … in condizione di join con Django ORM?

Aggiungerlo al filtro non riesce a ottenere oggetti Post senza oggetti associati nella watchlist.

risposta

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

Felice codifica.

+2

sembra che fa acually la stessa cosa di filtro(). Per esempio. aggiungendo un parametro a WHERE, non a ON e, quindi, fornendo risultati vuoti se non ci sono oggetti watchlist. – HoverHell

+0

Ma, in realtà, buona idea. Ho perso il parametro "extra" di Count. Sembra che funzioni. – HoverHell

+0

... o forse no. "extra" sembra avere uno scopo un po 'diverso. – HoverHell

2

Risposta breve: in determinate condizioni - sì.

Quando SINISTRA in costruzione con GenericForeignKey, Django chiama GenericRelation.get_extra_restriction che aggiunge una condizione aggiuntiva alla clausola ON con restrizione "content_type_id".

Per "ForeignKey" questo metodo è anche chiamato da restituisce Nessuno.

È possibile utilizzare questo luogo per inserire restrizioni aggiuntive nella clausola ON, se si riesce a organizzare il codice per ottenere parametri di restrizione appropriati in un determinato momento.

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

Mi hai salvato la vita uomo :) –

0

Nell'uso v2.0 Django FilteredRelation

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