Captcha виджеты для newforms полей

Вашему вниманию предоставляю написание мной виджеты, которые реализуют защиту от спам-ботов в формах. Данные виджети можно использовать в любых формах. В данном примере они буду использоваться в форме добавления комментариев.

Думаю полезно будет обратить внимание начинающим джангистам.

И так ...

Первое что необходимо сделать - это импорт всех необходимых объектов

from django import forms
from django.forms.widgets import Input, flatatt
from apps.blog.models import Comment
from django.forms.util import ValidationError
from random import choice
from settings import PROJECT_PATH, MEDIA_ROOT, MEDIA_URL, CAPTCHA_IMG, CAPTCHA_BG, CAPTCHA_FONT, SECRET_KEY
import Image, ImageDraw, ImageFont, sha

Готово

Да! Из фала settings.py ми импортим настроки нашей каптчи. Настроки виглядят таким образом:

CAPTCHA_IMG = 'images/captcha.jpg' # путь к картинке-каптчи
CAPTCHA_BG = 'images/captchabg.jpg' # путь к подложке
CAPTCHA_FONT = 'mulan.ttf' # путь к шрифту

Все пути указаны относительно MEDIA_ROOT

Затем пишем виджет для поля которое будет вставлять картинку каптчи в форму.

class CaptchaImageInput(Input):
    input_type = 'image'
    def render(self, name, value, attrs=None):
        attrs = {'src': MEDIA_URL + CAPTCHA_IMG }
        final_attrs = self.build_attrs(attrs, name=name)
        output =<input type="'+self.input_type+'" id="id_captcha_image" %s></input>' % flatatt(final_attrs)
        return output

Далее нам необходим виджет который бы делал скритое поле с хешем.

class CaptchaHashInput(Input):
    input_type = 'hidden'
    def render(self, name, value, attrs=None):
        value = ''
        SALT = SECRET_KEY[:20]
        imgtext = ''.join([choice('QWERTYUOPASDFGHJKLZXCVBNM') for i in range(7)])
        imghash = sha.new(SALT+imgtext).hexdigest()
        im=Image.open(MEDIA_ROOT + CAPTCHA_BG)
        draw=ImageDraw.Draw(im)
        font=ImageFont.truetype(MEDIA_ROOT + CAPTCHA_FONT, 22)
        draw.text((12,4),'&nbsp; '+imgtext, font=font, fill=(0,0,0))
        temp = MEDIA_ROOT + CAPTCHA_IMG
        im.save(temp, "JPEG")
        attrs = {'value':imghash}
        final_attrs = self.build_attrs(attrs, name=name)
        output ='<input type="'+self.input_type+'" %s></input>' % flatatt(final_attrs)
        return output

Что все это значит?

  • генирируем строку слачайних букв
  • создаем sha хеш строки случаних букв
  • открываем изображение-подложку для будущей картинки-каптчи
  • открываем файл шрифта, которым будем писать на изображении-подложке
  • пишем нашу строку на картинку-подложку
  • сохраняем полученую картинку-каптчу по адресу указаному в настройках

Кроме этого нам еще необходимо поле куда будут вводиться буквы с изображения-каптчи

class CaptchaTextInput(Input):
    input_type = 'text'
    def render(self, name, value, attrs=None):
        value = ''
        attrs = {'src': MEDIA_URL + CAPTCHA_IMG }
        final_attrs = self.build_attrs(attrs, name=name)
        output = '<input type="text" id="id_captcha_text" %s></input>' % flatatt(final_attrs)
        return output

Виджеты готовы. Теперь будем их использова в форме для добавления комментариев.

class CommentForm(forms.ModelForm):
    text = forms.CharField(label="Оставить клмментарий", widget=forms.Textarea(), error_messages={'invalid': 'Неверный формат поля!','required':'Обязательное поле!'})
    name = forms.CharField(label="Имя", error_messages={'invalid': 'Неверный формат поля!','required':'Обязательное поле!'})
    email = forms.EmailField(label="Email", error_messages={'invalid': 'Неверный формат поля!','required':'Обязательное поле!'})
    web = forms.URLField(label="Web", required=False, error_messages={'invalid': 'Неверный формат поля!','required':'Обязательное поле!'})
    captcha_image = forms.CharField(label="Image", widget=CaptchaImageInput(), required=False)
    captcha_hash = forms.CharField(label="Hash", widget=CaptchaHashInput())
    captcha_text = forms.CharField(label="Text", widget=CaptchaTextInput(), max_length=20, error_messages={'invalid': 'Неверный формат поля!','required':'Обязательное поле!'})
    class Meta:
        model = Comment
        fields = ('text','name','email','web')

Вот наглядный пример использования виджетов.

И еще на закуску, метод который проверяет совпадает ли веденная пользователем строка символов со стрококой на картинке-каптче (метод принадлежит классу CommentForm).

def clean_captcha_text(self):
    SALT = settings.SECRET_KEY[:20]
    hash = sha.new(SALT+self.cleaned_data['captcha_text']).hexdigest()
    if self.cleaned_data['captcha_hash'] != hash:
        raise ValidationError('Неправильный текст с картинки')
    else:
        return ''

Вот и все.Вы можете оцень работу виджетов чуть ниже :) , и черкнуть пару строк в коментарии.


Опубликовано в категории IT с тегами

Отзывов: 1


poloniumv ответил в Wednesday 24 December 2008

Спасибо за статью! Долго, конечно, размышлял что/куда/к_чему =), но в итоге повесил и себе на песочницу капчу =)


Оставить комментрий