DjangoDjango

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

Sep 19, 2014 · Updated: Jul 12, 2021 · by Tim Kamanin

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:

{% 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:

comment_tags.py
import django_comments
from django_comments.templatetags.comments import register, RenderCommentListNode


@register.tag
def render_custom_comment_list(parser, token):
    """
    This is our custom comment list template tag.
    """
    return RenderCustomCommentListNode.handle_token(parser, token)


class RenderCustomCommentListNode(RenderCommentListNode):
    """
    We created our custom Render Comment List Node that extends default RenderCommentListNode.
    """

    def get_query_set(self, context):
        qs = super(RenderCustomCommentListNode, self).get_query_set(context)

        # The only additional thing we do here is we prefetch_related('user') to prefetch related user objects in one query.
        qs = qs.prefetch_related("user")

        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!

Hey, if you've found this useful, please share the post to help other folks find it:

There's even more:

Subscribe for updates

  • via Twitter: @timonweb
  • old school RSS:
  • or evergreen email ↓ ↓ ↓