Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django exclude from annotation count

I have following application:

from django.db import models


class Worker(models.Model):
    name = models.CharField(max_length=60)

    def __str__(self):
        return self.name


class Job(models.Model):
    worker = models.ForeignKey(Worker)
    is_completed = models.BooleanField()

I want to annotate Workers query with count of completed jobs.

I'll try to do it with following script:

from myapp.models import Worker, Job
from django.db.models import Count

w = Worker.objects.create(name='Worker1')
Job.objects.create(worker=w, is_completed=False)
Job.objects.create(worker=w, is_completed=False)
Job.objects.create(worker=w, is_completed=True)
Job.objects.create(worker=w, is_completed=True)

workers = Worker.objects.all().annotate(num_jobs=Count('job'))
workers[0].num_jobs    
# >>> 4
workers = Worker.objects.all().exclude(job__is_completed=False).annotate(num_jobs=Count('job'))
# >>> []

Result of the last query is empty. How to exclude elements from reverse relation?

Django 1.8, python 2.7

UPD. I would like to have all workers in queryset, even those, who has a zero jobs

like image 956
Nikolai Golub Avatar asked Aug 06 '15 09:08

Nikolai Golub


People also ask

What is difference between annotate and aggregate in Django?

Unlike aggregate() , annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet ; this QuerySet can be modified using any other QuerySet operation, including filter() , order_by() , or even additional calls to annotate() .

What is OuterRef Django?

to Django users. According to the documentation on models. OuterRef: It acts like an F expression except that the check to see if it refers to a valid field isn't made until the outer queryset is resolved.

What is aggregate Django?

Essentially, aggregations are nothing but a way to perform an operation on group of rows. In databases, they are represented by operators as sum , avg etc. To do these operations Django added two new methods to querysets.

How does annotate work in Django?

Django annotations 2 are a way of enriching the objects returned in QuerySets. That is, when you run queries against your models you can ask for new fields, whose values will be dynamically computed, to be added when evaluating the query. These fields will be accessible as if they were normal attributes of a model.


1 Answers

update: ok I played a bit with this to generate the solution and I think I got it using Conditional Expressions:

Conditional expressions let you use if ... elif ... else logic within filters, annotations, aggregations, and updates. A conditional expression evaluates a series of conditions for each row of a table and returns the matching result expression.

Note: Conditional Expressions (such as Case and When) are new in Django 1.8, as pointed out by @Pynchia

from django.db.models import IntegerField, Sum, Case, When

workers = Worker.objects.annotate(
              num_jobs=Sum(
                  Case(
                      When(job__is_completed=True, then=1),
                      default=0,  
                      output_field=IntegerField()
                  )
               )
           )

now, each worker will have a num_jobs which will be an Integer that shows how many completed jobs that worker has :)

like image 132
Bogdan Goie Avatar answered Oct 01 '22 19:10

Bogdan Goie