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),' '+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 ''
Вот и все.Вы можете оцень работу виджетов чуть ниже :) , и черкнуть пару строк в коментарии.
Отзывов: 1
Спасибо за статью! Долго, конечно, размышлял что/куда/к_чему =), но в итоге повесил и себе на песочницу капчу =)
Оставить комментрий