How to get comments working with Django StaticGenerator

6comments

25th October 2010 in Coding Tags: django, performance, programming, staticgenerator

If like me you are using Django StaticGenerator to speed up your blog you should have noticed that your comments won't work anymore, since StaticGenerator will cache also the fields used by the django comment app to block spam and CSRF attacks.

In this post I'll share with you a quick and easy solution using jQuery.

When My Server Crashed Badly...

When I launched this blog I decided to disable the caching of the single posts because I didn't have enough time to look for a solution that would make it work with StaticGenerator

I soon found my server crashing badly when I got loads of traffic coming from stumbleupon... and that was really bad: infact all the stumblers would rate my site down because it wasn't working properly. So instead of getting loads of thumbs up, reviews and traffic I instead got my server down, all my sites not working, some clients annoyed and some thumbs down for my articles.

I had to find a solution for that!

Solution: get the Comment Form Asynchronously

This might not be the best solution, but it took me about 15 minutes to get it working and it solved the problem: my server didn't crash anymore, and that's what is important!

How does this work? Simple: let's create an ajax view that retrieves the post and then pass it to a template that just prints the comment form. Then we'll add some jQuery code to retrieve the comment form asynchronously.

The View

# views.py

from blog.models import Post
from django.shortcuts import get_object_or_404
from django.template import RequestContext

def ajax_comment_form(request, id):
    """
    Display comment form for requried post
    """
    post = get_object_or_404(Post, pk=id)
    
    context = { 'post': post }
    
    return render_to_response('blog/ajax_comment_form.html', context, context_instance=RequestContext(request))

Change "get_object_or_404(Post)" with the correct model name you are using in your project and "blog/ajax_comment_form.html" with the right path to the template we'll create in a moment.

The URL

# urls.py

urlpatterns = patterns('',

    url(r'^commentform/(?P<idgt;\d+)/$',
        view='blog.views.ajax_comment_form',
        name='ajax_comment_form'
    )
)

Change 'blog.views.ajax_comment_form' with the right path to the view.

Ajax Comment Form Template

Create the template "ajax_comment_form.html" in the right path according to what you've set in the file view.py. This file will contain just two django template tags:

{% load comments %}
{% render_comment_form for post %}

Tweak your Blog Post Detail Template

Open the template for you post detail page and simply add a wrapper div tag for your comment form named "form2replace":

<div id="commentformcontainer">
   {% if object.allow_comments %}
   <h3>Leave your comment</h3>
   <div id="commentform">

      <!-- add <div id="form2replace"> -->
      <div id="form2replace">
          {% render_comment_form for object %}
      </div>

   </div>
   {% else %}
   <h3 class="functional"><span>Comments are closed.</span></h3>
   
   <div id="commentform">
       <p>Comments have been closed for this post.</p>
   </div>
   {% endif %}
</div>

The jQuery

Assuming that you're already loading jQuery in your website, this is the code I used:

<script type="text/javascript">
//<![CDATA[

$(function() {
    f = $("#form2replace");
    if(f.length > 0){
        $.ajax({
            type: "POST",
            url: "{% url ajax_comment_form object.id %}",
            dataType: "html",
            success: function(response) {
                f.html(response);
            }
        });
    }
}

//]]>
</script>

Just change object.id with the name of the right variable name containing the id of your post.

A Step Further: External Javascript File

Since this Javascript will be the same for all the articles in your blog, it wouldn't be a bad idea to save it in an external javascript file so it would be cached by the browser.

But hey, wait a moment! There's {% url %} tag here.. how to put that in an external js file?

First of all create the file "ajax_comment_form.js" that will contain the jQuery code with a slight tweak: 

// ajax_comment_form.js

$(function() {
    f = $("#form2replace");
    if( f.length > 0){
        $.ajax({
            type: "POST",
            url: __comment_form_url__,
            dataType: "html",
            success: function(response) {
                f.html(response);
            }
        });
    }
}

Then at the end of your template file add the following code:

<script type="text/javascript">var __comment_form_url__ = "{% url ajax_comment_form object.id %}"</script>
<script src="{{ MEDIA_URL }}/js/ajax_comment_form.js" type="text/javascript"></script>

Again change object.id and the right path to your js file.

Do you have a better solution? Share it with me...

I know this solution is not the perfect one. It would be better to not query the database at all and avoid to use javascript.

Unfortunately the perfect solution needs more time to be implemented and I just didn't have that recently.

But if you did then please share it with me! :-)

Retweet

Comments

  1. 1.

    JagoanLeks said:

    ( on 3rd of November 2010 at 22:30 )

    sorry I'm still a beginner in this hall.

    Can you teach me?

    Usually I just download the complete template / layout.

    T__T

  2. 2.

    me said:

    ( on 2nd of March 2011 at 19:13 )

    Just a test!
    greetings

  3. 3.

    Béres Botond said:

    ( on 18th of March 2011 at 12:06 )

    I believe this is a nice compromise between speed and functionality. Staticgenerator is lightning fast since well it's just about serving static html, however that's going to be a problem with any dynamic page sections.
    For best performance I think the next step would be to cache the comments also separately with something like memcache. (or even better...staticgenerator :P)

  4. 4.

    Federico Capoano said:

    ( on 14th of September 2011 at 11:13 )

    @Bères Botond:

    There would be no point of caching the comment form with static generator, otherwise why would I have ever done this hack in the first place?

    The comment form cannot be cached because it contains the django csfr token that changes for every user.
    Another solution would be to try generating the csfr token dynamically with javascript or to eliminate it completely, but i'm not sure these solutions are much better than the one proposed here.

  5. 5.

    Federico Capoano said:

    ( on 24th of October 2011 at 12:31 )

    Now that I have more experience with django I don't get why I just didn't disable the csrf protection for the comment form! :-D

  6. 6.

    halcion said:

    ( on 5th of February 2012 at 14:34 )

    Staticgenerator is lightning fast since well it's just about serving static html, however that's going to be a problem with any dynamic page sections. Thanks .

Comments are closed.

Comments have been closed for this post.

Categories

Let's be social

Popular posts

Latest Comments

  1. I got very good results with this, thanks for sharing.

    By Yasir Atabani in How to speed up tests with Django and PostgreSQL

  2. Hi Amad, for any question regarding OpenWISP, use one of the support channels: http://openwisp.org/support.html

    By Federico Capoano in How to install OpenWISP

  3. Sir please guid , i have install the ansible-openwisp2 , now how to add the access points . What is the next procedure . Please help.

    By Ahmad in How to install OpenWISP

  4. Hi Ronak, for any question regarding OpenWISP, use one of the support channels: http://openwisp.org/support.html

    By Federico Capoano in netjsonconfig: convert NetJSON to OpenWRT UCI

  5. Hi, I have installed openwisp controller using ansible playbook. Now, i am adding the configurations automatically using OPENWRT devices in openwisp file by specifying shared_key so can you suggest me if I want to set limit to add configuration how can i do it?

    By Ronak in netjsonconfig: convert NetJSON to OpenWRT UCI

Popular Tags

battlemesh censorship creativity criptography django event fosdem google-summer-of-code ibiza inspiration javascript jquery linux nemesisdesign netjson ninux nodeshot open-source openwisp openwrt performance photo programming python security staticgenerator talk upload wifi wireless-community