piątek, 7 maja 2010

Ajax w Django. Dajax Project w akcji

Natchnęło mnie kiedyś (już nawet dość dawno) żeby przetestować bibliotekę Dajax do Ajaxa w Django.
Napisałem prostą aplikacyjkę w stylu guestbook.

Potrzebowałem oczywiście dajaxa, którego można sciągnąć ze strony: http://www.dajaxproject.com/
Dajax współpracuje z kilkoma frameworkami JavaScriptowymi, mianowice: jQuery, Prototype, MooTool i Dojo.

No to do dzieła: w settings.py dodajemy wpisy:
DAJAX_JS_FRAMEWORK = "prototype"
DAJAX_MEDIA_PREFIX = "dajax" # http://domain.com/dajax/
DAJAX_CACHE_CONTROL = 10 * 24 * 60 * 60
DAJAX_FUNCTIONS = (
    #Ajax funtions registered to examples.ajax
    'guestbookapp.ajax.pagination',
    'guestbookapp.ajax.send_form',
)

ENTRIES_ON_PAGE = 2
Będę korzystał z prototype, dodatkowo zarejestrowałem dwie funkcje:
send_form - do dodawania nowego wpisu do mojego guestbook'a i pagination do stronicowania wpisów ... ale o nich później.

Teraz ważny trick w urls.py musimy w dodać wpis:
urlpatterns += patterns('',
    ...
    # dajax handler
    (r'^%s/' % settings.DAJAX_MEDIA_PREFIX, include('dajax.urls')),
    ...

To tyle w konfiguracji samego środowiska django. Teraz możemy przejść do tworzenia samej aplikacji, nazwijmy ją guestbook.

plik models.py, chyba niczym tu nie zaskocze - jedna klasa:
from django.db import models

class Entry(models.Model):
    author = models.CharField(u'author', max_length=50)
    email = models.EmailField(blank=True, max_length=50)
    content = models.TextField(u'greeting')
    pub_date = models.DateTimeField(u'added at', db_index=True, auto_now_add=True)
    
    class Meta:
        verbose_name = 'Entry'
        verbose_name_plural = 'Entries'
        ordering = ('-pub_date',)

    def __unicode__(self):
        return self.author

Nie muszę chyba opisywać co zawiera wpis w księdze gości ;)

W zasadzie będziemy mieli tylko jedną stronę, wszystkie requesty będą kierowane przez ajaxa.

Zawartość pliku views.py:
from guestbook.utils import render_response
from django.conf import settings
from django.views.generic import list_detail
from models import Entry
from forms import EntryForm 

def get_pagination_page(page=1):
    from django.core.paginator import Paginator, InvalidPage, EmptyPage
    from django.template.loader import render_to_string
    paginator = Paginator(Entry.objects.all(), 2)
    try:
        page = int(page)
    except ValueError:
        page = 1
    try:
        items = paginator.page(page)
    except (EmptyPage, InvalidPage):
        items = paginator.page(paginator.num_pages)
    return items

def start(request):
    items = get_pagination_page(1)
    context = {
        "form" : EntryForm(),
        "items" : items,
    }
    return render_response(request,'guestbookapp/entry_list.html', context)

Widok start to jedyna strona startowa z formularzem i listą wpisów.

I czas opisać opisać zarejestrowane funkcje (ajax.py):
from django.conf import settings
from dajax.core import Dajax
from models import Entry 

def pagination(request):
    from guestbook.guestbookapp.views import get_pagination_page
    from django.template.loader import render_to_string
    from django.core.paginator import Paginator, InvalidPage, EmptyPage
    try:
        page = int( request.POST['p'] )
    except:
        page = 1
    paginator = Paginator(Entry.objects.all(), settings.ENTRIES_ON_PAGE)
    try:
        items = paginator.page(page)
    except (EmptyPage, InvalidPage):
        items = paginator.page(paginator.num_pages)
    render = render_to_string('guestbookapp/pagination_page.html', { 'items': items })
    dajax = Dajax()
    dajax.assign('#pagination','innerHTML',render)
    return dajax 
 
Paginacja, w zmiennej settings.ENTRIES_ON_PAGE przechowuje liczbę wpisów na stronie

def send_form(request):
    from dajax.utils import deserialize_form
    from forms import EntryForm

    dajax = Dajax()
    form_data = deserialize_form( request.POST.get('form') )
    form = EntryForm(form_data)
    print form
    if form.is_valid():
        from django.core.paginator import Paginator, InvalidPage, EmptyPage
        from django.template.loader import render_to_string
        form.save()
        dajax.removeCSSClass('#add_entry_form input','error')
        form.save()
        #dajax.alert("This form is_valid(), your mail is: %s" % form.cleaned_data.get('email'))
        paginator = Paginator(Entry.objects.all(), settings.ENTRIES_ON_PAGE)
        try:
            items = paginator.page(1)
        except (EmptyPage, InvalidPage):
            items = paginator.page(paginator.num_pages)
        render = render_to_string('guestbookapp/pagination_page.html', { 'items': items })
                
        dajax = Dajax()
        dajax.assign('#pagination','innerHTML',render)
        dajax.assign('#add_form', 'innerHTML', '')
    else:
        dajax.removeCSSClass('#add_entry_form input','error')
        for error in form.errors:
            dajax.addCSSClass('#id_%s' % error,'error')
    return dajax
Wysyłanie formularza ajaxem, w rosponse'ie otrzymujemy informacje o błędach, które są potem podmieniane w widoku.
Zauważcie, że nie musimy bawić się z serializację np. JSONem, wszystko zrobią za nas metody zawarte w dajax.utils odpowiedzialne na przykład za de-serializację formularzy.

Jak to wygląda w akcji?

To tyle, miłej zabawy ajaxem.