Показаны сообщения с ярлыком django. Показать все сообщения
Показаны сообщения с ярлыком django. Показать все сообщения

суббота, 27 ноября 2010 г.

Используем reCaptcha в приложениях django

Progg it

Сегодня мы поговорим об использовании reCaptcha в django-приложениях. Не буду говорить о достоинствах reCaptcha, думаю, что они и так понятны. Итак, наша задача состоит в том, чтобы как можно меньшими усилиями прикрутить reCaptcha к нашему приложению. Для этого нам потребуется выполнить следующее:

  • Зарегистрироваться здесь и получить наши ключи
  • Сделать приложение django, которое будет отвечать за взаимодействие с серверами reCaptcha, и позволит использовать ее в наших формах
  • Включить ее в одну из форм приложения, где она требуется

Шаг 1. Регистрация

Думаю, что как регистрироваться может разобраться любой из тех, кто понял что ему нужна reCaptcha в разрабатываемом приложении. Главное получить и сохранить ключи для вашего приложения. В зависимости от вашего желания вы можете получить ключи на конкретный адрес, или на все. Отмечу сразу, что любая пара валидных ключей корректно работает с адреса 127.0.0.1, что позволяет писать и отлаживать приложение на локальной машине, и не огребать при этом лишних проблем. Полученные ключи пропишем в settings.py примерно таким образом:

  ...
  #reCAPTCHA keys  
  RECAPTCHA_PUBLIC_KEY = < ПУБЛИЧНЫЙ КЛЮЧ > 
  RECAPTCHA_PRIVATE_KEY = < СЕКРЕТНЫЙ КЛЮЧ >
  ... 

На этом подготовительный этап закончен.

Шаг 2. Приложение django

Создадим приложение django, которое будет предоставлять функциональность другим приложениям и скрывать детали взаимодействия с сервисом reCaptcha. Скажу честно, что я взял приложение marcofucci, и только слегка его модифицировал.

Для начала необходимо скачать recaptcha-client. При этом нам потребуется только captcha.py из клиента. Берем этот файлик и кладем в наше приложение. Он обеспечит нам базовое взаимодействие с сервисом. Теперь нам необходимо сделать виджет и поле формы, для того, чтобы можно было легко использовать reCaptcha в нашем приложении. Приведу сразу код, который взят у marcofucci:

widgets.py

  1:  # -*- coding: utf-8 -*-  
  2:  from django import forms  
  3:  from django.utils.safestring import mark_safe  
  4:  from django.conf import settings  
  5:  from recaptcha import captcha  
  6:  class ReCaptcha(forms.widgets.Widget):  
  7:    recaptcha_challenge_name = 'recaptcha_challenge_field'  
  8:    recaptcha_response_name = 'recaptcha_response_field'  
  9:    def render(self, name, value, attrs=None):  
  10:      return mark_safe(u'%s' % captcha.displayhtml(settings.RECAPTCHA_PUBLIC_KEY))  
  11:    def value_from_datadict(self, data, files, name):  
  12:      return [data.get(self.recaptcha_challenge_name, None),   
  13:        data.get(self.recaptcha_response_name, None)]   

forms.py

  1:  # -*- coding: utf-8 -*-  
  2:  from django.conf import settings  
  3:  from django import forms  
  4:  from django.utils.encoding import smart_unicode 
  5:  from django.utils.translation import ugettext_lazy as _  
  6:  from recaptcha.widgets import ReCaptcha  
  7:  from recaptcha import captcha  
  8:  class ReCaptchaField(forms.CharField):  
  9:    default_error_messages = {  
  10:      'captcha_invalid': _(u'Invalid captcha')  
  11:    }  
  12:    def __init__(self, *args, **kwargs):  
  13:      self.widget = ReCaptcha  
  14:      self.required = True  
  15:      super(ReCaptchaField, self).__init__(*args, **kwargs)  
  16:    def clean(self, values):  
  17:      super(ReCaptchaField, self).clean(values[1])  
  18:      recaptcha_challenge_value = smart_unicode(values[0])  
  19:      recaptcha_response_value = smart_unicode(values[1])  
  20:      check_captcha = captcha.submit(recaptcha_challenge_value,   
  21:        recaptcha_response_value, settings.RECAPTCHA_PRIVATE_KEY, {})  
  22:      if not check_captcha.is_valid:  
  23:        raise forms.util.ValidationError(self.error_messages['captcha_invalid'])  
  24:      return values[0] 

Теперь мы готовы к использованию reCaptcha в нашем приложении.

Шаг 3. Использование

Использование сводится к созданию в форме соответствующего поля, и вполне обычной обработки формы в стиле django. Напиример так:

  1:  class RegistrationForm(ModelForm):  
  2:       recaptcha = ReCaptchaField(error_messages = {  
  3:            'required': u'Это поле должно быть заполнено',            
  4:            'invalid' : u'Указанное значение было неверно'  
  5:            })  
  6:       class Meta:  
  7:            model = UserData  
  8:            fields = (  
  9:                 'email',  
  10:                 'fio',  
  11:                 'phone',  
  12:                 'company',  
  13:                 'address'  
  14:            )  

В данном случае у меня имеется форма по модели, к которой добавлено поле с reCaptcha. Использование формы в функции вида приводить не буду, так как оно ничем не отличается от стандартного, достаточно заглянуть в документацию

вторник, 24 ноября 2009 г.

Документация Django в chm и pdf формате

Нарыл сегодня документацию для django, да и не только, для того чтобы использовать на ноуте. У меня часто нет интернета на ноуте, и я далеко не все помню из документации, что вполне естественно. А Django-book не совсем нравится, там не все есть, в документации которую рекомендуют использовать на сайте чёрт ногу сломит - всё таки 21 век, а там txt файлы. Вот, малец погуглив, накопал тут.

среда, 8 апреля 2009 г.

Наследование шаблонов в Django

В питоновском веб-фреймворке django встроен механизм наследования шаблонов страниц. Лично я считаю, что это очень спорная фишка и должна применяться с большой аккуратностью. Сейчас попробую объяснить почему.
Сначала определимся с терминологией. Этот механизм является именно наследованием, тем самым, которое используется в ООП. Этот вывод я сделал проанализировав получающиеся конструкции. Ведь фактически шаблон-наследник знает о структуре шаблона предка, хотя может и не знать детали реализации, ведь для того, чтобы переопределить (или доопределить) часть исходного шаблона нам потребуется указать имена тех частей, которые необходимо переопределить. Итак, рассмотрим маленкий пример:
Родительский шаблон:
<html>
<head>
<meta equiv="Content-type" content="text/html; charset=utf-8" />
<link type="text/css" rel="stylesheet" href="/static/Styles.css" />
{% block extrahead %} {% endblock %}
<title>{% block title %} {% endblock %}</title>
</head>
<body>
{% block content %} {% endblock %}
</body>
</html>
Шаблон наследник:
{% extends "base.html" %}

{% block extrahead %}
<script type="text/javascript" src="additionalscript.js"></script>
{% endblock %}

{% block title %}
Супер заголовок
{% endblock %}

{% block content %}
...
{% endblock %}

Казалось бы все по джанговски и замечательно. Но! Работа с шаблонами реализованная таким образом таит немало неприятностей, но самая главная из них - шаблон более низкого уровня по иерархии знает о структуре шаблонов более высокого уровня. И не просто знает (что не стало бы проблемой при использовании подходящих конвенций), а просто обязан использовать эти сведения. Получается что шаблон более низкого уровня сильно связан с более абстрактным шаблоном, что не есть правильно и лишает подобную структуру гибкости.
Выход? Есть выход! Наследование шаблонов безусловно мощная вещь и позволяет избежать дублирования кода, но использовать её необходимо с аккуратностью, особенно в больших проектах. Использовать также, как и наследование ООП, проверяя действие принципов используемых в ООП. Лично я для себя проверяю возможность наследования отношением "является", наследование можно применять в случае, если в человеческом языке корректной будет фраза "<наследник> является <предком>". Таким образом, приведенный выше пример корректен, так как шаблон-предок, фактически, является "обобщенной страницей", а шаблон наследник - "конкретной страницей". Но в случаях добавления дополнительных элементов на страницу, контролов и прочего, на мой взгляд более правильным и менее пахнущим будет использование агрегации с использованием механизмов custom tags.