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)
|
Comments
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 ^^
#
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. ^^
#