Półtora roku temu opisałem jak zastosować AJAX w aplikacji napisanej w Django. Wybrałem wtedy tworzoną w Pythonowym stylu bibliotekę mochikit i Django 0.96. Opis cieszy się dużą popularnością, ale bogatszy o ponad rok doświadczeń wiem, że teraz zrobiłbym to wszystko o wiele lepiej.
Kiedyś jako przykład użycia ajax stworzyłem proste wiki, ale nie chciało mi się tego opisać. Tym razem wyjaśnię jak napisać prymitywny blog w Django (a jakże!). Pominę jednak kwestię przyjemnego interfejsu i skupię się na jak największej ilości JavaScriptowych wodotrysków.
Wybór biblioteki JavaScript
Swój pierwszy kod w JavaScript napisałem chyba ponad trzy lata temu. Jedyne co pamiętam to biblioteka której użyłem - mootools. Potem zacząłem używać mochikit, bo wydawało mi się, że nic wygodniejszego nie znajdę.
Obecnie, wszędzie gdzie mogę stosuję jQuery. Biblioteka z dobrą dokumentacją, która wiele prostych zadań pozwala wykonać zaskakująco szybko. A ponieważ jest popularna, na stronie z pluginami odnaleźć można wszystko, czego nie znajdzie się w core .
Dlaczego nie wybrałem X albo Y ? Nie potrzebuje niczego więcej poza łatwym w użyciu selektorem i paroma manipulatorami. Wszystko to zapewnia mi jQuery. Bardzo ważna okazała się również jakość kodu jaki powstaje. Używając jQuery, kod (o ile nie pisało go stado wściekłych małp) jest zaskakująco zwięzły i czytelny, przez to szybko można zmodyfikować lub poprawić cudzą pracę.
Aplikacja - blog
Tak jak pierwszym programem w nowym języku musi być Hello world!, tak pierwszą
aplikacją jaką napisze się w nowym frameworku webowym jest blog. Efektem
końcowym będzie moduł o tej samej funkcjonalności co
ostatnio, jednak tym razem wykonany to o wiele
lepiej.
Blog bez AJAX
Podstawowa wersja aplikacji bez ajax do pobrania z github. Jaki kod jest, każdy widzi , więc nie będę go opisywał linijka po linijce. Aplikacja jest wręcz prymitywna, aby nawet Ci mniej doświadczeni nie mieli problemów ze zrozumieniem co się dzieje.
Blog z AJAX
Pod tym samym adresem, jednak z innym numerem rewizji, dostępna jest wersja z ajax. Jest to ta sama aplikacja, wzbogacona głównie o parę linijek JavaScript. Wyrzuciłem także automatyczne generowanie forularza komentarzy, co jest całkiem dobrym sposobem na spamboty (i skutecznie blokuje możliwość komentarzy użytkownikom z wyłączonym JavaScript).
To czym jest AJAX pisano już tyle razy, że chyba nie ma potrzeby abym i ja to robił. Mimo, że słowo AJAX brzmi super fajnie i każda poważna strona musi tego używać (bo inaczej nie jest poważna i super fajna), warto wiedzieć że nie jest to żadna magia.
Porównanie najlepiej zacząć od
diff
obu wersji. W rewizji z ajax dodane zostały dwa pliki z kodem JavaScript (z czego
jeden z nich to biblioteka jQuery), niewielkie zmiany zaszły w szablonach i
urls.py. Pojawiły się nowe widoki i moduł utils/ajax.py.
blog/templates/blog/entry.html, templates/base.html
Ponieważ o wiele łatwiej znaleźć odpowiednie obiekty DOM gdy posiadają unikalne
id, zmodyfikowałem szablon wstawiając parę pustych elementów. Dołączyłem pliki
z kodem JavaScript.
utils/ajax.py
Pisząc w JavaScript asynchroniczne zapytania, zamiast XML wolę używać
JSON. Wszystkie widoki którymi obsługuję
takie zadania zwracają obiekt HttpResponse z danymi w odpowiednim formacie.
Ponieważ nie chce powtarzać kodu i za każdym razem sprawdzać czy zapytanie
rzeczywiście jest asynchroniczne, a potem konwertować obiekty Pythona na JSON i
zwracać HttpResponse, napisałem dekorator json_response. Jedyne o czym trzeba
pamiętać, to żeby funkcja dekorowana zwracała łatwo parsowalny obiekt.
blog/views.py, blog/urls.py
Pojawiły się trzy nowe widoki - get_comment_form, post_comment oraz
comment_preview, jednak tylko dwa z nich są bezpośrednio dostępne poprzez url.
Ponieważ chcę aby komentarze dodawać można było jedynie w asynchroniczny sposób,
zmieniłem widok entries_list tak, aby wszystkie zapytania POST obsługiwane
były przez post_comment.
Zadaniem get_comment_form jest zwrócenie formularza do komentarzy. Widok
dekorowany jest z użyciem json_response dlatego zwraca słownik. Dzięki temu że
do renderowania formularza użyłem oddzielnego szablonu i napisałem dla niego
osobny templatetag, mogę go teraz użyć i pod kluczem form trzymać gotowy
HTML, który potem wrzucam na stronę.
post_comment obsługuje POST, sprawdzając poprawność danych i zapisując
przesyłane komentarze. Zwraca słownik danych z kluczem status dzięki któremu w
JavaScript łatwo mogę się dowidzieć jak serwer zareagował na przesłane
informacje oraz w zależności od rezultatu. Jeśli formularz zawierał błędy,
form zawiera wyrenderowany formularz z informacją co należy poprawić. Jeśli
jednak dane były poprawne i zostały zapisane, comment zawiera wyrenderowany
komentarz. Komentarze, podobnie jak formularz, obsługiwane są osobnym
templatetagiem.
comment_preview to po prostu podgląd. Użytkownik przesyła dane, a serwer
niezależnie od ich poprawności próbuje utworzyć z tego komentarz, wrzuca do
szablonu, renderuje html i wysyła wynik.
statics/javascript/ajax_comments.js
ajax_comments.js zawiera cały kod JavaScript jaki napisałem na potrzeby tej aplikacji. Jeśli nie znasz JavaScript to najwyższy czas to zmienić. Warto też zapoznać się z możliwościami biblioteki jQuery.
Pierwsza funkcja która wykonana zostanie po załadowaniu strony to
getCommentForm,
która umieszcza na stronie formularz do komentowania. Używając
jQuery.get,
wysyłam do serwera GET, a obsługę odpowiedzi jaką ten udzieli przekazuje do
funkcji
getCommentCallback.
Jeśli wszystko działa jak należy,
showCommentForm
umieści w odpowiednim miejscu przekazany kod HTML, wzbogacając go o przycisk
podglądu. Ponieważ wysyłanie danych z formularza ma być obsługiwane przez
JavaScript, do obudwu przycisków podpinam odpowiednie funkcje -
submitForm
oraz
previewSubmit,
które wyglądają bardzo podobnie. Obie przesyłają POST z danymi z formularza, korzystając z
jQuery.post.
Różnią się jednak url pod jaki kierowane jest żądanie oraz funkcjami
obsługującymi odpowiedź serwera.
previewSubmitCallback
wrzuca otrzymane dane do kontenera comment-preview.
submitFormCallback
jest niewiele bardziej skomplikowana, ponieważ w zależności od otrzymanej
odpowiedzi wyświetla nowy formularz, bądź chowa formularz i wyświetla wysłany
przez użytkownika komentarz. Aby przeglądarka nie wysłała formularza w
tradycyjny sposób, z przeładowaniem strony, funkcja zwracać musi wartość
false.
Debugowanie
Na koniec mały hint . Pewnie każdy zna plugin
firebug. Otóż, jednym z wielu jego możliwości jest
logowanie komunikatów. Zamiast używać co najmniej niewygodnego alert(), lepiej
zastosować logowania na jakie pozwala
wtyczka ;)
Tomasz Elendt
24.08.2009
Radzę nie używać
const. opis const w dokumentacji JS 1.5 na MozDev.