Improving Number of Queries Generated by Django Comment's render_comment_list Template Tag

One of my Django apps uses Django Comments. To show a list of comments on a page I use this simple built-in template tag:

1
  1. {% render_comment_list for object %}

All is fine, but I noticed that it loads user object per every comment line. So if you have 50 comments on a page you'll end up with 50 queries to get comment author object. Not a good thing but can be easily fixed. What we need here is to leverage Django ORM's prefetch_related() and load user object with a comment list on one go. (Of course you can go with select_related here, but I prefer prefetch_related here). Ok the fix is easy, we need to create our custom render_custom_comment_list template tag, that inherits almost everything from the default render_comment_list except one thing: a queryset. Here's how I do it: 1) Create custom template_tag file and call it like 'comment_tags.py' or whatever. 2) And then write the following contents:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
  1. # comment_tags.py
  2. import django_comments
  3. from django_comments.templatetags.comments import register, RenderCommentListNode
  4. @register.tag
  5. def render_custom_comment_list(parser, token):
  6. """
  7. This is our custom comment list template tag.
  8. """
  9. return RenderCustomCommentListNode.handle_token(parser, token)
  10. class RenderCustomCommentListNode(RenderCommentListNode):
  11. """
  12. We created our custom Render Comment List Node that extends default RenderCommentListNode.
  13. """
  14. def get_query_set(self, context):
  15. qs = super(RenderCustomCommentListNode, self).get_query_set(context)
  16. # The only additional thing we do here is we prefetch_related('user') to prefetch related user objects in one query.
  17. qs = qs.prefetch_related('user')
  18. return qs

As an outcome, instead of having 50+1 queries to get 50 comments out of the database, we got only 2: one to get comments out of db, another to get user objects. If you replace prefetch_related() with select_related() you will go down to only one query to load comments and user objects in one go. That simple!