Tuesday, July 5, 2011

ReCaptcha on Django

These steps are a simplified/less-hassle version of marcofucci's directions. Thank you marcofucci for helping me setting up recaptcha initially.

1. Get your public and private recaptcha keys

2. Add keys to your settings: settings_local.py, or settings.py if you don't have your code in public
        RECAPTCHA_PUBLIC_KEY = 'insert your public key'
        RECAPTCHA_PRIVATE_KEY = 'insert your private key'

3. Download Python's Recaptcha-client
        1. cd to the directory, e.g. recaptcha-client-x.x.x
        2. python setup.py install

Click for alternative steps 3 and 4
3. pip or easy_install to get Python's Recaptcha-client

4. don't copy anything

5. all the same except the line
from your_app.captcha import submit, displayhtml
is changed into
from captcha import submit, displayhtml

4. Copy captcha.py to your app folder: cp recaptcha-client-x.x.x/recaptcha/client/captcha.py path_to_your_django/apps/your_app So now you should see that this exists: path_to_your_django/apps/your_app/captcha.py

5. Add ReCaptchaField into your forms Differences to marcofucci's step 4 are highlighted.
#add to path_to_your_django/apps/your_app/forms.py

from django.conf import settings
from django import forms
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe

from your_app.captcha import submit, displayhtml

class ReCaptchaField(forms.CharField):
    default_error_messages = {
        'captcha_invalid': _(u'Invalid captcha')
    }

    def __init__(self, *args, **kwargs):
        self.widget = ReCaptcha
        self.required = True
        super(ReCaptchaField, self).__init__(*args, **kwargs)

    def clean(self, values):
        super(ReCaptchaField, self).clean(values[1])
        recaptcha_challenge_value = smart_unicode(values[0])
        recaptcha_response_value = smart_unicode(values[1])
        check_captcha = submit(recaptcha_challenge_value,
            recaptcha_response_value, settings.RECAPTCHA_PRIVATE_KEY, {})
        if not check_captcha.is_valid:
            raise forms.util.ValidationError(self.error_messages['captcha_invalid'])
        return values[0]

class ReCaptcha(forms.widgets.Widget):
    recaptcha_challenge_name = 'recaptcha_challenge_field'
    recaptcha_response_name = 'recaptcha_response_field'

    def render(self, name, value, attrs=None):
        return mark_safe(u'%s' % displayhtml(settings.RECAPTCHA_PUBLIC_KEY))

    def value_from_datadict(self, data, files, name):
        return [data.get(self.recaptcha_challenge_name, None),
            data.get(self.recaptcha_response_name, None)]

6. Put it in my form! In contrast to, marcifucci's version, I use the built-in forms.
#add to path_to_your_django/apps/your_app/forms.py

from django.contrib.auth import forms as auth_forms

class UserCreationForm(auth_forms.UserCreationForm):
    recaptcha = ReCaptchaField(label="I'm a human")

class AuthenticationForm(auth_forms.AuthenticationForm):
    recaptcha = ReCaptchaField(label="I'm a human")

7. See my examples on github:
- step 4 copied in captcha.py
- step 5, 6 forms.py

8. If you have more questions, feel free to email me.

No comments:

Post a Comment