Django annotate count with a distinct field

Question:

I have two models defined loosely like this:

class InformationUnit(models.Model):
    username = models.CharField(max_length=255)
    project = models.ForeignKey('Project')
    ...

class Project(models.Model):
    name = models.CharField(max_length=255)

Now, in a view, I want to annotate all the InformationUnits that belong to a project, so I do this:

p = Project.objects.all().annotate(Count('informationunit')

which works just ok.

Furthermore, I want to know, in each project, how many distinct usernames participate.
That is, count how many distinct usernames are there in the InformationUnits that compose one project.
I have tried the following, but it simply counts the number of InformationUnit, regardless of the username:

p = Project.objects.all().annotate(Count('informationunit__username')

Note that username is not an object, it is a string. Is there a clean way to do this or should I create a more complicated code based on loops and spaghetti code 😛

Thanks a lot!

Asked By: fenomenoxp

||

Answers:

Project.objects.all().annotate(Count('informationunit__username', 
                                     distinct=True))
Answered By: Rag Sagar

Count can take a distinct argument, like so:

p = Project.objects.all().annotate(Count('informationunit__username', 
                                         distinct=True))

This doesn’t seem to be documented, but you can find it in the source for Count.

Answered By: spencer nelson

If you just want to count the distinct values, you can use the distinct() and count() functions:

count = Project.objects.values('informationunit__username').distinct().count()
Answered By: Mouscellaneous

SQL SELECT field1, COUNT(DISTINCT(pk)) FROM project GROUP BY field1 ORDER BY NULL;

QuerySet

Project.objects.all().values(field1).annotate(count=Count('pk', distinct=True)).order_by()
Answered By: WeizhongTu
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.