Using Akismet/TypePad AntiSpam with Django's new comments framework
I've just recently started getting lots of spam in my comments. I was originally using a custom OpenID-enabled commenting app that I had written, but decided to switch to the new Django commenting system since it looked interesting. The honeypot doesn't seem to be working though, because spam's still getting through...
Although django-comment-utils provides similar functionality, it hasn't yet been updated to use the new django.contrib.comments. For those of you that are interested, here's how you can use Akismet to protect your blog.
UPDATE: TypePad's AntiSpam service is 100% API compatible with Akismet, so the code below works nicely with it as well.
Sign up at Wordpress to get your API key for Akismet. Paste it into your settings file:
AKISMET_API_KEY = 'your-key-here'
If you'd rather use TypePad's AntiSpam service, paste instead the following:
TYPEPAD_ANTISPAM_API_KEY = 'your-key-here'
Download the Python Akismet module and put akismet.py somewhere on your PYTHONPATH.
Now paste the following code into any file that gets imported from your Django project. I'm using my own custom blog app, so this went at the end of my blog's models.py file.
from django.contrib.comments.signals import comment_was_posted
def on_comment_was_posted(sender, comment, request, *args, **kwargs):
# spam checking can be enabled/disabled per the comment's target Model
#if comment.content_type.model_class() != Entry:
# return
from django.contrib.sites.models import Site
from django.conf import settings
try:
from akismet import Akismet
except:
return
# use TypePad's AntiSpam if the key is specified in settings.py
if hasattr(settings, 'TYPEPAD_ANTISPAM_API_KEY'):
ak = Akismet(
key=settings.TYPEPAD_ANTISPAM_API_KEY,
blog_url='http://%s/' % Site.objects.get(pk=settings.SITE_ID).domain
)
ak.baseurl = 'api.antispam.typepad.com/1.1/'
else:
ak = Akismet(
key=settings.AKISMET_API_KEY,
blog_url='http://%s/' % Site.objects.get(pk=settings.SITE_ID).domain
)
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):
comment.flags.create(
user=comment.content_object.author,
flag='spam'
)
comment.is_public = False
comment.save()
comment_was_posted.connect(on_comment_was_posted)
This code can be tweaked to delete the comment outright if Akismet or TypePad detects that it's spam - connect instead to the comment_will_be_posted signal and return False. The flag is created so that a script can go through and periodically delete all spam.
Thanks to Coulix.net for the original implementation.
UPDATE: Fixed encoding issues when sending data to Akismet. UPDATE #2: TypePad AntiSpam support.
Comments
-
Fíam
says...
I suggest you to check my approach to spam blocking http://fi.am/entry/preventing-spam/ (doesn't require any external service). I went from more than 300 spam comments per day to 1 in three months.
-
Fiam
says...
I received an unicode error after posting the comment, but it got recorded anyway. So I checked you code for sending the data to Akismet and I spotted two small errors: you must .encode('utf8') comment.user_name and comment.comment before putting them on the wire, othewise non-ascii data will raise an exception. On the other hand, set settings.DEBUG = False ;)
-
Oscar
says...
Thanks! Now I don't have to figure out how to do this myself... :-D
And btw, you need to skin your post preview :-)
-
trbs
says...
related question, are the speed issue's with akismet solved already ?
last time i tried to use akismet from a server in europe it easily took 10s to get an answer back from akismet. which is just too slow for any real usage...
-
Samuel Cormier-Iijima
says...
Fíam: Thanks for pointing out those mistakes - I've updated the code to fix it. See, I leave debugging on so that readers like you can fix my code for me :-)
trbs: I've just started using Akismet, but haven't really noticed any speed issues...
-
Kyle
says...
Solid code, but I still don't like the idea of having to maintain and include a separate file just to get Akismet functionality. I really wish Akismet would get merged into the
django.contrib.commentsand operate on an opt-in basis (say, if AKISMET_API_KEY has been defined in setting.py).It just feels so un-djangolike to always be dropping in a script like this into all your projects...
-
Julien Phalip
says...
Thanks a lot for sharing! Very useful and easy to set up.
-
John
says...
Could you write a plugin for Mollom?
-
Anil
says...
Hi, I only just saw your (very interesting!) work here, and wanted to see if you were interested in making it work with <a href="http://antispam.typepad.com/">TypePad AntiSpam</a>. It should be 100% API compatible with Akismet, but the engine is open source and the service is free no matter how many comments you get -- a good fit for high-demand Django sites. And there are a good number of Django fans at Six Apart anyway, so we'd be happy to see TypePad AntiSpam used in combination. :)
-
Samuel Cormier-Iijima
says...
Anil: Thanks for pointing out AntiSpam - I had never heard of it before, but it looks really good. It's nice that AntiSpam is compatible with Akismet, so that
akismet.pyworks with it as well. I've updated the code with a few simple changes to make it work with both depending on which key is specified insettings.py. -
Sofeng
says...
Any plans for using OpenID with Django's New Comments?
-
Jens
says...
thanks for sharing your code. works well for me. is your script for deleting the spam comments also available?
-
Stephane Daury
says...
I'm sure the crew would love to have you join in at MontrealPython4, On September 25th, if you're interested. http://montrealpython.org/?p=38
-
Mike
says...
Hey, Fellow McGiller here... Great work, here and on chide.it. Would you drop me a line to meet on campus some time? Let's talk Django and Facebook and other interesting stuff...
-
Yeago
says...
I'm not sure how this code could work with the syntax error at the first 'if hasattr' line (hasattr should take 'TYPEPAD_ANTISPAM_API_KEY' not TYPEPAD_ANTISPAM_API_KEY.
Also, assuming the content object has 'author' is also bad news. Preferable to pull another hasattr check there, too.
Fixes below: http://www.djangosnippets.org/snippets/1255/
-
Physical Condition
says...
I spotted two small errors: you must .encode('utf8') comment.user_name and comment.comment before putting them on the wire, othewise non-ascii data will raise an exception. On the other hand, set settings.DEBUG = False ;)
-
Kolossos
says...
Great! Thank you.
-
Bill Bartmann
says...
Cool site, love the info.
-
Nanou
says...
Molto interessante blog che ho bruciacchiato per il RSS tradotto tramite RssItaliano
-
joe
says...
I'm using FCCV and it's great. One improvement would be to scan comment.user_name along with comment body as sometimes that's where the blacklisted words will be.
-
Auto Insurance Guy
says...
Ah!!! at last I found what I was looking for. Somtimes it takes so much effort to find even tiny useful piece of information. Nice post. Thanks
-
Kwess
says...
I’d passion to ascertain that too!
-
Escort in London
says...
It is certainly interesting for me to read the blog. Thanks for it. I like such topics and everything that is connected to this matter. I definitely want to read a bit more soon.
-
autoomob
says...
?????? ??? ??????? ??? ????????.
-
mastepoc
says...
? ?? ??????, ??? ?????????? ????????? ? ? ????????? ????? ?? ?????, ??? ????????????? ??????
-
Django forum
says...
Where get Entry models?
-
LayeveAdvenda
says...
java ???????»???¶?µ?????µ ?????±???»?????‹?? ?????°???µ?? ?????°?‡?°?‚?? ?????°?‡?°?‚?? ?????±???»?????‹?? ?????°???µ?? ?????????·?? ?????µ?¶???? http://www.pyzam.com/profile/3314400 ?????±???»?????‹?? ?????°???µ?? ?????‚?????????? ?‚?µ?»?µ?„?????° ?????°?‡?°?‚?? ?????°?‡?°?‚?? ?????±???»?????‹?? ?????°???µ?? ???µ?????€?µ??
-
Ben Keating
says...
This is a great article. I'm using it now in several production environments.
-
fluituild
says...
winsome answers i like it
-
Video
says...
Thnaks Admin
-
polokean
says...
Great list with some I missed, so thanks! (Hey that rhymed :) )
-
Led Lighting
says...
Its quite difficult to avoid, especially if you don't have the time to moderate each comment. Good to see implementations of some of the methods that are out there though..
-
splbkeans
says...
??????? ???-?? ?????????? ??? ???, ??????? ?????, ??????? ??????
-
ladysman
says...
Cool post, but just realised you've got a new design. It looks awesome man, much better than the old one! Nice one! :D
-
Chat
says...
Thank you
-
Brandon Taylor
says...
You can get the current site without passing in the primary key:
Site.objects.get_current().domain
Cheers
-
hey
says...
test

Latest Entries