Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Updating Django OSQA to use reCaptcha 2

Our support site is built on OSQA which in turn is built on Django.  It was still using reCaptcha (version 1) which was taken over by Google, and discontinued.  So it was time to roll up our sleeves and update to reCaptcha 2.

The main idea is the reCaptcha is a field based on a widget.  In OSQA for example, when a user submits a question and their reputation is low, the question form adds a spam check field to the form using essentially

self.fields[‘recaptcha’] = ReCaptchaField

ReCaptchaField is defined as

class ReCaptchaField(forms.Field):
    def __init__(self, *args, **kwargs):
        super(ReCaptchaField, self).__init__(widget=ReCaptchaWidget)

class ReCaptchaWidget(forms.Widget):

NOTE: If you copy this code, notice that WordPress has changed the single and double-quote marks.  You’ll need to change them back to the simple characters used in code.

The ReCaptchaWidget renders HTML of the reCaptcha which is essentially

Note that you need a PublicKey and a PrivateKey that you obtain from Google when signing up for reCaptcha.

When the form is posted, the reCaptcha will post an additional field, g-recaptcha-response, along with the form post.

The ReCaptchaField will take that posted field and send it to a function (‘submit’ in this case) which will do a post to Google’s recaptcha/api/siteverify page to verify the reCaptcha was solved correctly.  If it was solved correctly, json is returned with success : true.  That needs to be captured and interpreted.  You can see how this is done on Google’s reCaptcha page.

So, without further ado, here is the code:

In osqa/forum_modules/recaptcha/

This is pulling in the public and private keys from Django settings

from forum.settings Import EXT_KEYS_SET
from forum.settings.base import Setting

label = “Recaptch public key”,
help_text = “””
Get this key at reCaptcha to enable
recaptcha anti spam through.

label = “Recaptch private key”,
help_text = “””
This is the private key you’ll get in the same place as the recaptcha public key.

In osqa/forum_modules/ we have some simple glue code:

from formfield import ReCaptchaField

def create_anti_spam_field():
    return (‘recaptcha’, ReCaptchaField())

Things start getting interesting in /osqa/forum_modules/

from django import forms
from lib import captcha
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode, smart_unicode
from django.utils.translation import ugettext_lazy as _
import settings
import json

class ReCaptchaField(forms.Field):
    def __init__(self, *args, **kwargs):
        super(ReCaptchaField, self).__init__(widget=ReCaptchaWidget)

def clean(self, value):
    super(ReCaptchaField, self).clean(value)
    recaptcha_response_value = smart_unicode(value)

    check_captcha = captcha.submit(recaptcha_response_value, settings.RECAPTCHA_PRIV_KEY, {})

    if not check_captcha.is_valid:
        raise forms.util.ValidationError(_(‘Invalid captcha ‘ + json.dumps(check_captcha.error_code)))

    return value

class ReCaptchaWidget(forms.Widget):
    def render(self, name, value, attrs=None):
        return mark_safe(force_unicode(captcha.displayhtml(settings.RECAPTCHA_PUB_KEY)))

    def value_from_datadict(self, data, files, name):
        return data.get(‘g-recaptcha-response’, None)

And finally to the actual reCaptcha handling in osqa/forum_modules/recaptcha/lib/

import urllib2, urllib
import json


class RecaptchaResponse(object):
    def __init__(self, is_valid, error_code=None):
        self.is_valid = is_valid
        self.error_code = error_code

def displayhtml (public_key):

    return “””

    “”” % {
              ‘PublicKey’ : public_key,

def submit (recaptcha_response_field,

    if not (recaptcha_response_field and
            len (recaptcha_response_field)):
        return RecaptchaResponse (is_valid = False, error_code = ‘incorrect-captcha-sol’)

    def encode_if_necessary(s):
        if isinstance(s, unicode):
            return s.encode(‘utf-8’)
        return s

    params = urllib.urlencode ({
        ‘secret’: encode_if_necessary(private_key),
        ‘response’ : encode_if_necessary(recaptcha_response_field),
        ‘remoteip’ : encode_if_necessary(remoteip),

    request = urllib2.Request (
        url = “https://%s/recaptcha/api/siteverify” % VERIFY_SERVER,
        data = params,
        headers = {
        “Content-type”: “application/x-www-form-urlencoded”,
        “User-agent”: “reCAPTCHA Python”

    httpresp = urllib2.urlopen(request)

    json_data_str =


    response_dict = json.loads(json_data_str)

    return_code = response_dict[‘success’];

    if return_code == True:
        return RecaptchaResponse(is_valid = True)
        return RecaptchaResponse(is_valid = False, error_code = response_dict[‘error-codes’])

The above files can be downloaded directly from here.

This post first appeared on Network Wrangler - Tech Blog | IT Tips, Tricks, Tu, please read the originial post: here

Share the post

Updating Django OSQA to use reCaptcha 2


Subscribe to Network Wrangler - Tech Blog | It Tips, Tricks, Tu

Get updates delivered right to your inbox!

Thank you for your subscription