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
- Template tag - list punctuation for a list of items by shapiromatron 9 months, 4 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Please login first before commenting.