Blog

the writings of

Adding Akismet to Django Comments

December 20, 2010

How to add an Akismet spam filter to Django's comments app.

Despite Django's best efforts to use a honeypot-style spam filter, I have still had problems with spam entries using Django's built-in comment system. With a little poking around, I was able to find Django's documentation on the signals sent by their comments app. I've always had a good experience with Akismet when using WordPress and I'm quite fond of the service they provide. So, I figured I'd get Akismet hooked into my Django comments.

First, I used David Lynch's Akismet Python Library, which I found linked in Akismet's plugins and libraries. Then, I just modified his example to fit the Django framework.

I stuck the following code in my models:

from django.contrib.comments.signals import comment_will_be_posted
import akismet

def spam_check(sender, comment, request, **kwargs):
    akismet.USERAGENT = "David Lynch's Python library/1.0"

    my_api_key = "API KEY GOES HERE"    

    try:
        real_key = akismet.verify_key(my_api_key,"http://www.example.com")
        if real_key:
            is_spam = akismet.comment_check(my_api_key,"http://www.example.com",request.META['REMOTE_ADDR'], request.META['HTTP_USER_AGENT'],comment_content=comment.comment)
            if is_spam:
                return False
            else:
                return True
    except akismet.AkismetError, e:
        print 'Something went wrong, allowing comment'
        print e.response, e.statuscode
        return True

comment_will_be_posted.connect(spam_check,sender=Comment,dispatch_uid="comment_spam_check_akismet")

There are a couple things to note here. First, if the whole mechanism fails, I allow the comment to be posted. That way, if Akismet changes their API or something, the comments will still post (allowing spam) until i can get in there to update the code. Second, in practice, things like the API key should be placed in your settings file, then referenced as normal (settings.AKISMET_KEY or something).

If you are using a customized comments app, with Django's suggested mechanisms, you simply change the signal connection a little...

comment_will_be_posted.connect(spam_check,sender=CustomCommentModel,dispatch_uid="comment_spam_check_akismet")

I should mention that I didn't spend any time looking around to see if there was already a Django snippet out there to accomplish this. It was an easy enough implementation that it seemed like it was worth just writing it out myself.

If there's a more robust Akismet snippet for Django, I'd love to see it. Just post a link in the comments below (Now, with Akismet spam filter!).

blog comments powered by Disqus