2015-08-06 10 views
5

sto avendo problemi con il nuovoannotazioni su più tavoli con Django 1.8 ORM

Diciamo che ho i seguenti 3 modelli:

class Author(models.Model): 
    name = models.TextField() 

class Book(models.Model): 
    author = models.ForeignKey(Author, related_name='books') 
    title = models.TextField() 
    is_fiction = models.BooleanField() 

class SpeakingEvent(models.Model): 
    author = models.ForeignKey(Author, related_name='events') 
    date = models.DateField() 

e volevo ottenere un singolo set di query di Autori annotato con il numero di libri di narrativa pubblicati e il numero di futuri interventi in lingua parlata.

Quindi, posso effettuare le seguenti operazioni:

Author.objects.all().annotate(
    future_speaking=Sum(Case(
     When(events__date__gte=timezone.now(), 
      then=1), 
     default=0)), 
    fiction_count=Sum(Case(
     When(books__is_fiction=True, 
      then=1), 
     default=0)), 
) 

Tuttavia, i numeri risultanti sono troppo alti. Se ci sono m libri e n eventi, allora io finisco nello <correct_result> * m per il conteggio degli eventi, <correct_result> * n per il conteggio dei libri. Questo è causato dal modo in cui Django unisce i due tavoli insieme con un join sinistro. I risultati sono corretti se ometto una delle annotazioni.

C'è un modo per cambiare i join è rimuovere i duplicati con una clausola when?

+1

Questo sembra essere questo: https://docs.djangoproject.com/en/1.8/topics/db/aggregation/#combining-multiple-aggregations allevamento è la testa. Sfortunatamente il mio caso non è solo limitato a Count(), ma aggiungerò una soluzione alternativa che ho trovato – JeffS

risposta

1

Quello che ho finito è fondamentalmente contando e dividendo in codice.

Author.objects.all().annotate(
future_speaking_divide_count=Count('events'), 
future_speaking=Sum(Case(
    When(events__date__gte=timezone.now(), 
     then=1), 
    default=0)), 
fiction_count=Sum(Case(
    When(books__is_fiction=True, 
     then=1), 
    default=0)), 
fiction_count=Count('books') 
)