Prevent Django newcomments spam with Akismet (reloaded)

This is a rewrite of my previous post about preventing spam for Django's new comments framework. By using the moderation features that are available, the spam prevention can be done in a much nicer and robust way. Assuming you have an Entry model representing blog posts, you can paste the following below it in your models.py file:

from django.contrib.comments.moderation import CommentModerator, moderator
from django.contrib.sites.models import Site
from django.conf import settings

class EntryModerator(CommentModerator):
    def check_spam(self, request, comment, key, blog_url=None, base_url=None):
        try:
            from akismet import Akismet
        except:
            return False

        if blog_url is None:
            blog_url = 'http://%s/' % Site.objects.get_current().domain

        ak = Akismet(
            key=settings.AKISMET_API_KEY,
            blog_url=blog_url
        )

        if base_url is not None:
            ak.baseurl = base_url

        if ak.verify_key():
            data = {
                'user_ip': request.META.get('REMOTE_ADDR', '127.0.0.1'),
                'user_agent': request.META.get('HTTP_USER_AGENT', ''),
                'referrer': request.META.get('HTTP_REFERER', ''),
                'comment_type': 'comment',
                'comment_author': comment.user_name.encode('utf-8'),
            }

            if ak.comment_check(comment.comment.encode('utf-8'), data=data, build_data=True):
                return True

        return False

    def allow(self, comment, content_object, request):
        allow = super(EntryModerator, self).allow(comment, content_object, request)

        # change this depending on which spam provider you want to use
        spam = self.check_spam(request, comment,
            key=settings.AKISMET_API_KEY,
        ) or self.check_spam(request, comment,
            key=settings.TYPEPAD_ANTISPAM_API_KEY,
            base_url='api.antispam.typepad.com/1.1/'
        )

        return not spam and allow

moderator.register(Entry, EntryModerator)

This is more customizable than the signals approach and works well if other moderation features are being used. If you want to make comments that are flagged as spam become hidden instead of deleted, change the allow() method to moderate(). See also the Django snippet here.

Discuss this article on Reddit »