суббота, 10 июля 2010 г.

Django и AJAX

Итак, задача:

1. Ajax должен работать так же просто и эффективно как Django
2. Количество кода для средних задач должно быть настолько минимальным, насколько это возможно
3. Подключить Ajax-функцию должно быть не сложнее чем написать простейшую python-функцию

Решение:

Уж не знаю кто как решает эту задачу, но я уверен что почти каждый django-разработчик сталкивался с ней хотя бы раз в жизни. Вот и я однажды задумался по этому поводу. И почему-то мне захотелось использовать в решении этой задачи RPC. Настоящий такой, красивый и простой RPC...

И не знаю бы сколько велосипедов и паровозов я еще изобрел, если бы не наткнулся на один замечательный проект. Итак, внимание... DajaxProject.com

Судя по всему, проект еще достаточно зеленый, однако пользоваться библиотеками уже вполне можно и нужно. Кстати, о птичках. На сайте есть две библиотеки:

1. Dajaxice:
Связующее ядро dajaxproject. Ее основная цель заключается в банальном асинхронном взаимодействии в рамках кода на стороне сервера Django и вашего JavaScript-кода.

Работает оно примерно следующим образом:




2. Dajax:
Мощный инструмент для легкой и супер-быстрой разработки асинхронной логики в web-приложений с использованием Python и почти отсутствием JavaScript-кода.


Схема работы:



Итак, инструкция по применению:

1. Качаем стабильную версию Dajaxice и Dajax. Не забываем, что ядром является именно Dajaxice, поэтому оно всему и голова.
2. Распаковываем оба архива и в каждом поочередно делаем так:


$ sydo python setup.py install


3. В Вашем settings.py ищем INSTALLED_APPS и добавляем в самый низ две строки:


INSTALLED_APPS = ( 
'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions', 
'django.contrib.sites',
...
 'dajaxice', 
 'dajax', 
...
 )


4. Смотрим, чтобы TEMPLATE_LOADERS выглядели примерно так. Если нужно, редактируем:


TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
    'django.template.loaders.eggs.Loader',
)


5. Добавляем новую переменную DAJAXICE_MEDIA_PREFIX в settings.py:


DAJAXICE_MEDIA_PREFIX="dajaxice"


6. В urls.py в самом конце добавляем новую строку:


urlpatterns = patterns('',
    ...
    (r'^%s/' % settings.DAJAXICE_MEDIA_PREFIX, include('dajaxice.urls')),
    )

7. Если необходимо, добавляем импорт в urls.py:


from django.conf import settings

8. Выбираем приложение, в котором нам нужно создать RPC-вызовы и создаем там новый модуль ajax.py. Я например, предпочитаю такие вещи хранить отдельно, поэтому создал отдельное приложение jsrpc.

9. Собственно пишем первый метод, который обработает наш AJAX-запрос:


# -*- coding: utf-8 -*-
from django.utils import simplejson 
from dajaxice.core import dajaxice_functions 

def primer(request,message):
    return_message=u'Полученное сообщение: {0}'.format(message)
    return simplejson.dumps({'message':return_message})


10. В settings.py делаем так, чтобы новый метод был виден для AJAX-запросов:


DAJAXICE_FUNCTIONS = (
        'jsrpc.ajax.primer',
         )

11. В шаблоне, в пределах тега пишем так:


{% load dajaxice_templatetags %}{% dajaxice_js_import %}

12. Создаем кнопку чтобы проверить работоспособность:


<input onclick="Dajaxice.jsrpc.primer('primer_callback',{'message':'Хэллоу Уорлд!'});" type="button" value="Push Me!" />


Перевожу... В onclick мы должны указать какую из подключенных функций мы будем юзать. После Dajaxice нужно указать только приложение и метод в модуле ajax.py. В нашем примере получается Dajaxice.jsrpc.primer. 

Далее, в качестве первого параметра указываем callback, в который возвратить данные, чтобы потом разгребать средствами JavaScript. В нашем случае - primer_callback, его мы создадим позже.

Ну и как же без набора параметров... Если мы что-то хотим передать серверу, пишем точно также как обычно передаем из сервера в шаблоны. В данном случае, мы просто передаем строку на сервер. А сервер нам должен вернуть ее же. Не забываем объявить параметр message в параметрах метода, иначе ничего не получится.

13. Напишем callback:


<script type="text/javascript">
function primer_callback(data){
    if(data!=Dajaxice.EXCEPTION){
        alert(data.message);
    }else{
        alert('Error');
    }
}
</script>



Обратите внимание, что мы получаем "свыше" уже сериализованные данные, что, безусловно, очень удобно.

14. Должно работать:


До сих пор мы пользовались только первой библиотекой - ядром Dajaxice. Что же нам могут предложить во второй библиотеке, если итак все уже шоколадно?


Скажу от себя, что предлагают нам не совсем "правильные" вещи, хотя и достаточно удобные.


Изначально Django проектировался так, чтобы полностью исключить любую возможную логику в шаблонах. И наоборот, серверная логика не должна знать вообще о существовании шаблонов, об их устройстве и структуре HTML. Если нам захотелось поменять верстку в шаблонах, это никак не должно отражаться на серверном коде. И это правильно. То что описано ниже, напрочь противоречит всем правилам! Однако, как бы то ни было, считаю своим долгом рассказать о том "неправильном" подходе, который предлагает библиотека Dajax, а дальше - выбирайте сами.


Так как мы уже подключили практически все необходимое, остается лишь одна маленькая деталь. В скачанном и распакованном архиве django-dajax-0.8.4 идем в каталог src/ и выбираем нужную библиотеку, в зависимости от того, какой JavaScript-фреймворк мы используем в проекте. Нам доступны:


1. Dojo
2. JQuery
3. Mootools
4. Prototype


Я пользуюсь JQuery, поэтому все нижеописанное будет на ее примере, хотя отличия для других библиотек незначительные.


1. Копируем jquery.dajax.core.js в каталог MEDIA_ROOT/js/.
2. В шаблоне, в пределах тега <head></head> подключаем эту самую библиотеку:


<script type="text/javascript" src="{{ MEDIA_URL }}/js/jquery.dajax.core.js" charset="utf-8"></script>


3. Подключили. Теперь создаем кнопочку и поле для вывода, чтобы почувствовать разницу в использовании:



<input type='button' value='Push Me!' onclick="Dajaxice.jsrpc.primer2('Dajax.process');" id='knopka'>
<div id='testarea'></div>


4. Создаем метод в уже созданном модуле


# -*- coding: utf-8 -*-
from django.utils import simplejson
from dajaxice.core import dajaxice_functions
from dajax.core import Dajax
...

def primer2(request):
    dajax = Dajax()
    dajax.assign('#knopka','value',u'Нажато')
    dajax.assign('#testarea','innerHTML',u'Бла-бла-бла')
    return dajax.json()


Обратите внимание, что значения для HTML-элементов Вы указываете именно на сервере. Это то о чем я писал выше. Неудобно, но зато JavaScript всего одна строка, да и то в пределах onclick. Решайте сами, использовать или нет.


5. Ну и подключаем метод в settings.py:


DAJAXICE_FUNCTIONS = (
        ...
        'jsrpc.ajax.primer2',
         )





6. Вот собственно и все. Теперь все должно работать:





пятница, 9 июля 2010 г.

Recaptcha и Django

Однажды мне понадобилось прикрутить каптчу к регистрации, к комментариям и еще в пару мест в одном из проектов. Из всех каптч мне по определению больше всего нравится сервис ReCaptcha. Не буду описывать плюсы и минусы, а просто поделюсь готовым решением.

1. Для начала качаем само приложение
2. Распаковываем (tar -xf django-recaptcha.tar.gz) в корне вашего проекта
3. В settings.py добавляем две константы:

RECAPTCHA_PUBLIC_KEY='бла-бла-бла'
RECAPTCHA_PRIVATE_KEY='бла-бла-бла'

4. Заменяем "бла-бла-бла" на то, что выдали в http://www.google.com/recaptcha
5. Далее, если мы хотим защитить от роботов форму регистрации, создаем в приложении для аккаунтов модуль forms.py и пишем туда примерно следующее:

from my_project.recaptcha.fields import ReCaptchaField
from django.contrib.auth.forms import UserCreationForm
...
class UserCreationFormExtended(UserCreationForm): 
    recaptcha = ReCaptchaField(label=u'Символы с картинки')

    def __init__(self, *args, **kwargs): 
        super(UserCreationFormExtended, self).__init__(*args, **kwargs) 
        self.fields['email'].required = True

    class Meta:
        model = User
...

6. Ну, и, собственно, в views.py, который рендерит регистрационную форму, пишем примерно так:

from forms import UserCreationFormExtended
...
form = UserCreationFormExtended()
return {'form': form}

Это все.

P.S. Приложение django-recaptcha, которое Вы скачали по ссылке выше, не имеет никакого отношения к любым другим. Это приложение было отчасти переписано, отчасти написано с нуля мной и имеет только русскоязычную версию. Если будет необходимо, сделаем multilanguage-вариант.

среда, 7 июля 2010 г.

Новое русскоязычное сообщество Django

Новое русскоязычное сообщество Django: проблемы с Django и python, идеи, наработки, нюансы, код, приложения, для гуру и новичков - и _всегда_ помогаем друг-другу:

1. Группа - http://groups.google.com/group/django_ru
#Обсуждения, мозговые штурмы, взаимопомощь и ответы на любые вопросы

2. Блог - http://django-ru.blogspot.com/
#Интересные и полезные статьи и уроки на русском

3. Исходные тексты - http://code.google.com/p/django-ru/
#Тут можно скачать полезные вещи для Django

Популярные вопросы и обсуждения:

- Django и ajax
- Формы в Django
- Модели в Django
- Редактирование базы данных в Django
- Изменение базы данных в Django
- Работа с email в Django
- Django CMS
- Django и шаблоны
- Django и админка
- Хостинг для Django
- Django и nginx
- Django и apache