Adding Captcha To Django's Built-in Comments
I recently had a good friend of mine ask for some help in adding a captcha field to his comments form. I gave him some pointers, but before he could put them into action he had to leave for a Thanksgiving roadtrip home. I didn't give much mind to the idea of putting captchas on my own site since it's not all that popular amongst spammers yet. When I woke up this morning, however, I found myself with a few spare minutes to see if my pointers were correct.
Some of the ideas I shared with my friend turned out to not work very well. As I tinkered about trying to get things to work on my own site, I think I came up with a relatively efficient way of doing things.
Installing The Captcha
The captcha field I use is quite simple and effective. I originally got it from http://django.agami.at/media/captcha/, but the project seems to be unmaintained now. Along the road to Django 1.0, some changes were made to the way form fields work, and there is a minor change required in the base code for this captcha field if you want it to work. Alternatively, you can use a copy of the field that I'm currently using.
All you need to do is extract the captcha directory somewhere on your PYTHONPATH. The author recommends putting it in django.contrib, but I usually just place it straight on the PYTHONPATH so all I need to do is from captcha import CaptchaField instead of from django.contrib.captcha import CaptchaField. Minor details...
Adding The Captcha
The first thing you'll want to do after installing the captcha field is add the field itself to your comments form. Instead of subclassing the built-in django.contrib.comments.forms.CommentForm form, I simply decorated the constructor of the form as such:
This adds a field called security_code to the CommentForm, and it works the same way as if you had done something like this:
from django import forms from captcha import CaptchaField class MyCommentForm(forms.Form): name = forms.CharField() ... security_code = CaptchaField() |
You can put the decorating snippet from above anywhere you'd like so long as the module you put it in is loaded at some point in your project. I usually put this sort of magic in my main urls.py file so it's harder to forget about when I debug things.
Fixing the Form
The first problem with this little trick seems to be that the CaptchaField is rendered as unsafe HTML in the default form.html template in the built-in comments application. That just means that, instead of seeing the captcha, you will see the HTML necessary to render the CaptchaField directly on the page, like this:
<input type="hidden" name="security_code" value="captcha.caZ1SqQ" /> <img src="/static/captchas/caZ1SqQ/0656f09d3974850397dd4c4974f23a35.gif" alt="" /><br /><input type="text" name="security_code" id="id_security_code" />
To fix that, you can apply the safe filter to the field and make the template look something like this:
Notice the {{ field|safe }} in there. Also note that I prefer the table layout for the comment form over the default mode. If you change your form template as I have done, you should put the updated copy in your own project's template directory. It belongs in templates/comments/form.html, assuming that your templates directory is called templates. You'll probably also want to check out the preview.html template for the django.contrib.comments application. I changed mine to look like this:
See how I just use the include tag to pull in the comments/form.html template I mentioned above? Saves a lot of typing and potential for problems... If you update the preview.html template, you should save your copy in templates/comments/preview.html, assuming your templates directory is called templates.
Testing It Out
At this point, you should be able to try out your newly installed captcha-fied comments. If it doesn't work, please comment on this article and perhaps we can figure out the problem!
Comments
Comments powered by Disqus