0

My App consists of a notification module. If the notifications are consecutively arrived from a same user, I would like to show "n notifications from john doe".

eg:

The database rows are as:

id    |   user    |     notif       |
------------------------------------
1       john doe     liked your pic 
2       john doe     commented on your pic
3       james        liked your pic
4       james        commented on your pic
5       john doe     pinged you
6       john doe     showed interest
7       john doe     is busy

The above notifications are to be shown as:

2 notifications from john doe
2 notification from james
3 notofications from john doe

How would I count these consecutive rows with same value in a column using django orm?

Notification.objects.all().values('user', 'notif_count').group_consecutive_by('user').as(notif_count=Sum())

Something like that. Please help.

6
  • If I understood your question right you want to implement some kind of notification history but with ordering by date and grouped by user? Commented Jan 10, 2019 at 8:03
  • I am not sure, but I don't think you can do that with Aggregation. What you can do is that 5 notifications from John Doe, 2 Notification from James. Commented Jan 10, 2019 at 8:34
  • @SergeyPugach yup! it is. Commented Jan 10, 2019 at 8:40
  • @ruddra It's possible(not with Aggregation solely) I have just found the solution. Will write it soon. Thanks. Commented Jan 10, 2019 at 8:40
  • 1
    @Shameless I am very interested in your solution, could you please post it here? Commented Jan 10, 2019 at 23:20

1 Answer 1

1

Let my model Notification model be:


Class Notification(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name='notifications',
        on_delete=models.CASCADE)
    notif = models.CharField(max_length=255)
    date_created = models.DateTimeField(auto_now_add=True)

The database rows are as:

id    |   user    |     notif       |
------------------------------------
1       john doe     liked your pic 
2       john doe     commented on your pic
3       james        liked your pic
4       james        commented on your pic
5       john doe     pinged you
6       john doe     showed interest
7       john doe     is busy

Basically, I am trying to join consecutive rows by user

The above notifications then are to be shown as:

2 notifications from john doe
2 notification from james
3 notofications from john doe

instead of

5 notifications from john doe
2 notification from james

or

1 notifications from john doe
1 notifications from john doe
1 notification from james
1 notification from james
1 notofications from john doe
1 notofications from john doe
1 notofications from john doe

In order to achieve this, we are looking for a dictionary like:

{
"john doe": ["notif1", "notif2"],
"james": ["notif1", "notif2"],
"john doe": ["notif1", "notif2", "notif3"] #duplicate key.
}

But, that's not possible as duplicate keys are not allowed. Hence I am going with array of tuples instead.

[
  ('john doe', ['notif1', 'notif2']),
  ('james', ['notif1', 'notif2']),
  ('john doe', ['notif1', 'notif2', 'notif3']),
]

So, we first sort the Notifications by date_created. Then we use itertools.groupby to make groups per user.

from itertools import groupby
from operator import attrgetter

qs = Notification.objects.select_related('user').order_by('date_created')
notifs= [(u, list(nf)) for (u, nf) in groupby(qs, attrgetter('user'))]

You have everything sorted as needed in notifs.

Done!

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer. I knew about groupby but hoped you've found the solution in SQL, which would be useful for further filtering/ordering.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.