Login

Simple random file CAPTCHA

Author:
jeverling
Posted:
March 7, 2012
Language:
Python
Version:
1.3
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. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

Please login first before commenting.