Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django ORM version of SQL COUNT(DISTINCT <column>)

Tags:

sql

orm

django

I need to fill in a template with a summary of user activity in a simple messaging system. For each message sender, I want the number of messages sent and the number of distinct recipients.

Here's a simplified version of the model:

class Message(models.Model):
    sender = models.ForeignKey(User, related_name='messages_from')
    recipient = models.ForeignKey(User, related_name='messages_to')
    timestamp = models.DateTimeField(auto_now_add=True)

Here's how I'd do it in SQL:

SELECT sender_id, COUNT(id), COUNT(DISTINCT recipient_id)
    FROM myapp_messages
    GROUP BY sender_id;

I've been reading through the documentation on aggregation in ORM queries, and although annotate() can handle the first COUNT column, I don't see a way to get the COUNT(DISTINCT) result (even extra(select={}) hasn't been working, although it seems like it should). Can this be translated into a Django ORM query or should I just stick with raw SQL?

like image 606
nephtes Avatar asked Feb 12 '13 18:02

nephtes


1 Answers

You can indeed use distinct and count together, as seen on this answer: https://stackoverflow.com/a/13145407/237091

In your case:

SELECT sender_id, COUNT(id), COUNT(DISTINCT recipient_id)
FROM myapp_messages
GROUP BY sender_id;

would become:

Message.objects.values('sender').annotate(
    message_count=Count('sender'),
    recipient_count=Count('recipient', distinct=True))
like image 183
Scott Stafford Avatar answered Oct 18 '22 16:10

Scott Stafford