django-notification: How many observed items
-
12-12-2019 - |
Question
I have a queryset at the moment that returns the number items in a model ordered by the number of people watching it. So I have a m2m field representing this link.
Ie:
#models.py
class MyModel(models.Model):
...
watchers = models.ManyToManyField(User, blank=True)
I would count the number of occurrences and order them by count in a default manager which was then used by the view.
Now I'm going over to using django-notification, using 'notification.ObservedItem' to allow users to watch an instance if MyModel.
So in my view when a user posts some content I have something like this:
notification.observe(object, request.user, 'new_object')
This works well.
Now, how can I generate a queryset representing all the objects of class MyModel, ordered by the number of people 'observing' them?
Solution
You can accomplish that by using annotations:
from django.db.models import Count
MyModel.objects.annotate(num_users=Count('watchers')).order_by('num_users')
OTHER TIPS
The problem is that django-notification uses generic foreign keys.
So I've redefined my watchers field:
watchers = generic.GenericRelation(notification.ObservedItem)
Then I can get all the watchers for a specific instance of MyModel.
$x = MyModel.objects.get(id=1)
$x.watchers.all()
$[<ObservedItem: ObservedItem object>, <ObservedItem: ObservedItem object>, <ObservedItem: ObservedItem object>]
$x.watchers.count()
$3
Close but no cigar. I wanted to do was something like this:
MyModel.objects.annotate(count=Count('watchers')).order_by('count')
Which is something that Django can't do, according to the docs.
Django's database aggregation API doesn't work with a GenericRelation.
Not to worry, I think this will probably help:
http://charlesleifer.com/blog/generating-aggregate-data-across-generic-relations/
Repo is here:
https://github.com/coleifer/django-generic-aggregation
I've not tried it out yet...