Login

Simple random file CAPTCHA

Author:
jeverling
Posted:
March 7, 2012
Language:
Python
Version:
1.3
Tags:
captcha random
Score:
0 (after 0 ratings)

This is a snippet for a simple CAPTCHA. A random image from a list of images is shown, and the form checks if the correct solution was given.
Normally I would use django-simple-captcha or maybe reCAPTCHA, but in this case I wanted to have a number of fixed images, nothing dynamically generated.
I wanted to include the contact form in multiple pages, most of which are direct_to_template generic views. However, passing the random image to the extra_context of direct_to_template didn't work, because the value was only initialized once on startup.
Therefore I pass the list of possible choices to extra_context, and use the template filter |random to select one image. The form's clean method will check if the correct solution was given when form.is_valid() is called in the view. If not, the view will display a new captcha.

Of course there are other, more elegant solutions like a custom template tag or overriding the generic view, but this works fine for me. Using a fixed number of images will probably not provide good protection for sites that are of much interest to spammers, but for smaller sites it should be sufficient.

You can see the CAPTCHA in action at http://www.lackieren-in-polen.de/

 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
*e.g. filecaptcha.py:*

    CAPTCHA_SOLUTIONS = {'01.png': ['alfa romeo', 'alfa-romeo', 'alfaromeo'],
                         '02.png': ['audi'],
                         ...
---

*urls.py:*

    extra_context = {'contact_form': MessageForm(), 'captcha_choices': CAPTCHA_SOLUTIONS.keys()}
---

*forms.py:*

    class MessageForm(forms.Form):
        captcha = forms.CharField(label='Spam protection')
        captcha_img = forms.CharField(required=False)
    
        def clean(self):
            if not self.data['captcha']:
                raise forms.ValidationError('This field is required.')
            if self.data['captcha'].lower() in CAPTCHA_SOLUTIONS.get(self.data['captcha_img']):
                return self.cleaned_data
            raise forms.ValidationError('Wrong solution')
---

*base.html:*

    {% if contact_form %}
    {% with captcha=captcha_choices|random %}
    <tr>
        <th><label for="id_captcha">{{contact_form.captcha.label}}</label></th>
        <td>{% if contact_form.non_field_errors %}
            {{contact_form.non_field_errors}}
            {% endif %}
            <input type="text" id="id_captcha" name="captcha">
            <input type="hidden" name="captcha_img" value="{{captcha}}"></td>
    </tr>
    <tr>
        <td></td>
        <td>
            <img src="{{MEDIA_URL}}image/captcha/{{captcha}}" alt="captcha" title="Spam protection image" width="107" height="70" />
        </td>
    </tr>
    {% endwith %}
    {% endif %}
---

*views.py (contact_form POST target):*

        form = MessageForm(request.POST or None)
        if form.is_valid():
            #save and redirect
        return render_to_response('contact.html',
                                  {'form': form,
                                   'captcha': random.choice(CAPTCHA_SOLUTIONS.keys()),
                                   },
                                  context_instance=RequestContext(request))

More like this

  1. Automatically create urls for templates in a directory by blackrobot 3 years, 9 months ago
  2. Captcha without Freetype or the Python Imaging Library (PIL) by gregb 6 years, 1 month ago
  3. Math Captcha Field and Widget by btaylordesign 3 years, 10 months ago
  4. FieldsetForm by Ciantic 8 years, 3 months ago
  5. Lorem Ipsum - Random content for your mockups by gfranxman 8 years, 5 months ago

Comments

Please login first before commenting.