ReCaptcha for django forms (improved and with remoteip)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
'''
ReCaptcha for django forms

All credits go to Marco Fucci, I used his idea here and adapted it to my needs.
Contact: Filip Sobalski <pinkeen@gmail.com>

How to use it:

In your settings.py add:

RECAPTCHA_PUBKEY = 'your recaptcha public key'
RECAPTCHA_PRIVKEY = 'your recaptcha private key'

After that just import and use ReCaptchaField in your form as you would any other field. That's it.

*** Important *** If you want to have peace of mind in case google decided that the remoteip parametr is mandatory then:
Derive every form that has the captcha field from ReCaptchaForm and when you create the form object after receiving POST/GET, pass a remoteip parameter like that:

form = YourCaptchaForm(data=request.POST, remoteip=request.META['REMOTE_ADDR'])
'''

from django import forms
from django.utils.safestring import mark_safe
from django.utils.encoding import smart_unicode

import settings

import urllib
import urllib2


class ReCaptchaWidget(forms.Widget):

	def get_recaptcha_widget_html(self, field_name):
		widget = u''
		widget += u'<div class="recaptcha_box" id="fdiv_%s"></div>' % field_name
		widget += u'<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>'
		widget += u'<script type="text/javascript">'
		widget += u'Recaptcha.create("%s", "fdiv_%s", {theme: "white"});' % (settings.RECAPTCHA_PUBKEY, field_name)
		widget += u'</script>'
		
		return widget
		
        def value_from_datadict(self, data, files, name):
		
		remoteip = None
		
		if 'REMOTE_ADDR' in data:
			remoteip = data.get('REMOTE_ADDR')
		
		return {
			'challenge' : data.get('recaptcha_challenge_field', None), 
			'response' : data.get('recaptcha_response_field', None),
			'remoteip' : remoteip
		}
	
	def render(self, name, value, attrs=None):
		return mark_safe(self.get_recaptcha_widget_html(name))
		
class ReCaptchaField(forms.Field):

	widget = ReCaptchaWidget
	required = True
	
	def verify_captcha(self, challenge, response, remoteip):
		url = 'http://www.google.com/recaptcha/api/verify'
		values = {
			'privatekey': settings.RECAPTCHA_PRIVKEY, 
			'challenge' : challenge, 
			'response' : response
		}
		
		if remoteip:
			values['remoteip'] = remoteip
			
		vrequest = urllib2.Request(url, urllib.urlencode(values))
		vresponse = urllib2.urlopen(vrequest)
		result = vresponse.read().split('\n')
		
		if result[0] == 'true':
			return (True, result[1])
			
		return (False, result[1])
		
	def clean(self, value):
		super(ReCaptchaField, self).clean(value['response'])
		
		result = self.verify_captcha(value['challenge'], value['response'], value['remoteip'])
		
		if not result[0]:
			raise forms.ValidationError('Wrong answer, try again.')
		
		return value['response']

		
class ReCaptchaForm(forms.Form):
	
	def __init__(self, data=None, remoteip=None, *args, **kwargs):
		if data and remoteip:
			data = data.copy()
			data['REMOTE_ADDR'] = remoteip
			
		super(ReCaptchaForm, self).__init__(data=data, *args, **kwargs)

More like this

  1. Semi-Portable recaptcha integration with django forms by pinkeen 2 years, 5 months ago
  2. reCAPTCHA integration by marco.fucci 3 years, 10 months ago
  3. RecaptchaForm by oggy 4 years, 11 months ago
  4. Simple, stand-alone reCaptcha form module by SmileyChris 3 years, 10 months ago
  5. Include captchas from recaptcha.net by b23 5 years, 7 months ago

Comments

iamwithprograms (on February 16, 2011):

Hey pinkeen, nice snippet.

Got a question for you though. Have you had any problems with the "recaptcha_challenge_field" and "recaptcha_response_field" inputs not existing in your POST data? It seems that using the javascript api prevents these fields from being added to my post data. When I disable javascript everything works fine... any ideas?

I know you have removed the captcha dependency but... it might be better to use it since captcha's displayhtml() method for rendering provides a noscript version of the field.

django 1.2.5 python 2.7 ^^

#

iamwithprograms (on February 16, 2011):

Nevermind. It turns out the template I was using surrounded the form with a table which caused the fields to not be posted. Moving the form elements to surround the table resolved this issue. ^^

#

(Forgotten your password?)