For a long time I've been meaning to find a more convenient way to filter comments. I really disliked the way we had to retrieve them through a tag, which either retrieved "all or nothing".
Sometimes it's necessary to retrieve comments from a subset of objects, such as comments for all blog posts "in category Cars".
To do this efficiently with minimal changes to the database, we'll need a proxy model. This proxy model has no table in the database but allows us to tweak the manager.
Firstly, define the proxy class and manager.
from django.conf import settings
from django.contrib.comments.managers import CommentManager
from django.contrib.comments.models import Comment
def comments_for_objects(self, objects):
This is the magic query that links the `django_comments` table to the selected range of objects.
The reason why we have to do this is because the django_comments.object_pk field is stored as an string.
By casting it to an integer, we can then link it back to the original model without errors.
It's a bit hackish, but it's the cleanest way I found find to get it working.
# The usual filters for comments
qs = self.for_model(objects.model)
qs = qs.filter(site = settings.SITE_ID, is_public = True, is_removed = False)
# Link objects to the comments table
# This is for PostgreSQL. I'm sure there's a matching cast for MySQL and such.
extra_where = 'CAST(django_comments.object_pk AS int) IN (%s)' % ','.join([ '%s' % obj.pk for obj in objects ])
return qs.extra(where = [extra_where]).order_by('-submit_date')
This dummy proxy class allows you to filter comments by certain objects.
proxy = True
objects = CommentObjectManager()
Now that the hard part is done, we just need a way to use it.
def for_posts_in_category(self, category, limit = 1500):
Example: Returns comments for the latest 1500 posts in the category given.
restriction = BlogPost.objects.all_in_category(category)[:limit]