<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Prettyprinted &#187; captcha</title>
	<atom:link href="http://prettyprinted.net/blog/tag/captcha/feed/" rel="self" type="application/rss+xml" />
	<link>http://prettyprinted.net/blog</link>
	<description>Django, Python and Drunken Ramblings</description>
	<lastBuildDate>Thu, 26 Nov 2009 21:45:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Subclassing Django&#8217;s CommentForm</title>
		<link>http://prettyprinted.net/blog/subclassing-djangos-commentform/</link>
		<comments>http://prettyprinted.net/blog/subclassing-djangos-commentform/#comments</comments>
		<pubDate>Mon, 24 Nov 2008 18:32:03 +0000</pubDate>
		<dc:creator>steingrd</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[captcha]]></category>
		<category><![CDATA[comments]]></category>

		<guid isPermaLink="false">http://prettyprinted.net/blog/?p=20</guid>
		<description><![CDATA[Django comes with batteries included and a very powerful and useful battery is the django.contrib.comments framework. However, to make it in time for the long awaited 1.0 release the comments framework was released without customization hooks. See #8630 for more details.
The long story in a short sentence is that you cannot subclass or customize CommentForm [...]]]></description>
			<content:encoded><![CDATA[<p>Django comes with batteries included and a very powerful and useful battery is the <code>django.contrib.comments</code> framework. However, to make it in time for the long awaited 1.0 release the comments framework was released without customization hooks. See <a href="http://code.djangoproject.com/ticket/8630">#8630</a> for more details.</p>
<p>The long story in a short sentence is that you cannot subclass or customize <code>CommentForm</code> in todays version without getting your hands dirty.</p>
<p>I recently enabled <a href="http://en.wikipedia.org/wiki/Captcha">Captcha</a> verification to comments on this site to prevent spammers from filling my database with non-public comments. Tor Brede Vekterli has <a href="http://arcticinteractive.com/2008/10/16/adding-recaptcha-support-django-10-comments/">written about how to do this</a> by using signals, but for technical reasons I&#8217;d rather not go down that road. So I landed on the next possible strategy, namely subclassing <code>CommentForm</code>.</p>
<p>My subclass is a standard Django form:</p>
<pre>class CaptchaCommentForm(CommentForm):
    captcha = forms.CharField(max_length=20, label='Enter this word')

    def clean_captcha(self):
        # verify self.cleaned_data['captcha'] here, details omitted,
        # raise forms.ValidationError if verification fails</pre>
<pre></pre>
<p>Since I wanted to control the way this field is displayed by adding an image I also edited my form template. In my <code>comments/form.html</code> template I added a check to include the captcha image:</p>
<pre>{% for field in form %}
    {% ifequal field.name "captcha" %}
        do whatever it takes to display the custom field.
    {% else %}
        display regular comment form field
    {% endifequal %}
{% endfor %}</pre>
<p>As I mentioned above the comments framework is not really designed to be extended or customized in this way. To make the framework use my <code>CaptchaCommentForm</code> instead of its own <code>CommentForm</code> I resorted to <a href="http://en.wikipedia.org/wiki/Monkey_patch">monkeypatching</a>!</p>
<p>The framework uses a single function, <code>comments.get_form</code>, whenever it needs a fresh <code>CommentForm</code> instance. What I wanted is for that function to return my <code>CaptchaCommentForm</code> instead. Here is what I did to my <code>urls.py</code>:</p>
<pre>from django.contrib import comments
from forms import CaptchaCommentForm

def override_get_form():
    return CaptchaCommentForm()
comments.get_form = override_get_form</pre>
<p>Thanks to the dynamic features of Python we can simply replace the original function with our own that returns the correct instance. Not pretty, but it works.</p>
]]></content:encoded>
			<wfw:commentRss>http://prettyprinted.net/blog/subclassing-djangos-commentform/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
