Tworzymy przykładowego bloga - część 2
Teraz stworzymy działającą aplikację wiadomości - listującą najnowsze wpisy, czy wyświetlającą wybrany wpis. W tym artykule zaprezentuję kolejną porcję możliwości Django jak i sposób tworzenia aplikacji w tym frameworku (dostępne rozwiązania i sposób ich użycia).
Widok ze stronicowaniem wpisów
W poprzednim artykule stworzyliśmy prosty widok listujący wszystkie wiadomości. Wykorzystaliśmy do tego prosty widok-funkcję:
W nowszych wersjach Django dostępne są także widoki-klasy (class based views). Jest to zbiór klas, na bazie których można szybciej tworzyć widoki określonego typu - np. widok listujący, widok szczegółowy pojedynczego wpisu, widok dodawania, czy edycji itd. Można oczywiście osiągnąć tą samą funkcjonalność używając widoku-funkcji, ale może to być mniej czytelne niż w przypadku widoków-klas.
Jako widok listujący wpisy użyjemy ListView:Dziedzicząc klasę ListView otrzymujemy całą potrzebną funkcjonalność. Wystarczy podać model. Dodatkowo określiłem paginate_by - ilość wiadomości wyświetlanych na jednej stronie, oraz context_object_name zawierającą nazwę zmiennej, pod którą lista wiadomości będzie dostępna w szablonie.
Szablon index.html także ulega zmianie. Domyślna nazwa szablonu dla tego widoku to news/news_list.html - i na taką zmieniłem nazwę/położenie tego pliku. Sam szablon zyskuje stronicowanie:
Zmienna is_paginated będzie ustawiona na True, jeżeli będzie więcej niż jedna strona stronicowania. Obiekt page_obj odpowiada za stronicowanie i możemy z niego wyciągnąć informacje takie jak poprzedni i następny numer strony.
Odnośniki do widoków
Linki do stronicowania są ustawione na sztywno w szablonie. Jeżeli zmienimy w urls.py przypisany widokowi adres URL to te linki przestaną działać. Framework dostarcza nam system generowania adresów URL na podstawie podanych nazw widoków.
W blog/urls.py mamy zmapowany nasz widok:
Widok szczegółowy
Mamy widok listujący wiadomości. Zróbmy teraz widok wyświetlający jeden konkretny wpis. Użyjemy do tego innego widoku-klasy - DetailView:
Kod jest naprawdę prosty. Dziedziczymy DetailView, podajemy model i tyle. W urls.py mapujemy widok na adres: W szablonie news/news_list.html dodajemy link: Oraz tworzymy szablon dla widoku - news/news_detail.html:Szablon jest prosty, ale wyświetli dane dotyczące wybranej wiadomości. Tutaj wykorzystujemy wbudowaną funkcjonalność DetailView - klasa ta potrafi pobrać wpis po podanym numerze ID lub właśnie po "slugu" - unikalnym tekstowym identyfikatorze. Nie musimy pisać dodatkowego kodu pobierającego rekord.
Lista wiadomości z danej kategorii
W naszych modelach są też kategorie. Każda wiadomość może być przypisana do wielu kategorii. Zróbmy teraz widok listujący wiadomości z wybranej kategorii. Musimy więc napisać drugi widok ListView, który będzie wyświetlał tylko pasujące wiadomości. Oto jedna z możliwych wersji widoku:
To rozwiązanie jest trochę inne od poprzednich. Zamiast dziedziczyć ListView wybrałem NewsList (który to dziedziczy ListView). Dziedziczenie już istniejącej klasy widoku pozwala czasami uniknąć sporych duplikacji kodu. W tym prostym przypadku dziedziczymy podany model i ilość wpisów stronicowanych na jednej stronie.
W tym widoku pojawiają się nowe metody. Jeżeli czytałeś artykuł o widokach opartych o klasy to od razu się połapiesz. Metoda get_context_data pozwala przekazać dane do szablonu. Operator super pozwala nam pobrać istniejący kontekst i dodać do niego rekord kategorii. W metodzie get_queryset określamy jakie wiadomości mają być wyświetlane - te przypisane do wybranej kategorii. Dodatkowo podałem nazwę szablonu - template_name. Gdybym tego nie zrobił używany byłby szablon dziedziczonej listy wiadomości (news_list.html).
W urls.py mapujemy widok:
Jak widzimy w adresie URL przekazujemy "slug" kategorii. Dlatego w widoku możemy użyć self.kwargs['slug'] by otrzymać wartość sluga wybranej kategorii. Co ważne - jeżeli kategoria o podanym slugu nie będzie istniała to kod rzuci wyjątek. O obsłudze takich przypadków napiszę nieco dalej.
Teraz dodajmy listowanie kategorii, do jakich został przypisany news: Szablon news/category_news_list.html wygląda podobnie do szablonu news_list:Duplikuje nam się trochę kodu. Zajmiemy się tym za chwilę. Mamy już obecnie trzy widoki - lista wszystkich wiadomości, lista wiadomości z wybranej kategorii i widok szczegółowy wiadomości. Nie musieliśmy ani pisać zapytań SQL do bazy danych, ani pisać wielu linii kodu Pythona.
Szablony Django
W tej chwili nasze szablony są bardzo "słabe". Listy wiadomości duplikują kod, jak i żaden szablon nie ma poprawnej struktury. Szablony Django oferują nam m.in. bloki oraz dziedziczenie szablonów. Dzięki temu w łatwy sposób jesteśmy w stanie zarządzać wieloma szablonami bez zbędnej duplikacji kodu.
W katalogu news/templates stworzyłem szablon base.html:
Mamy tutaj prosty szablon bazowy z strukturą strony HTML. Dodatkowo pojawiło się kilka bloków Django - na tytuł strony (zarówno ten w nagłówku jak i wyświetlany na stronie) oraz treść.
Szablon news/news_detail.html może wyglądać teraz tak:
Na samym początku pliku używamy taga extends i podajemy nazwę szablonu jaki dziedziczymy. Następnie wypełniamy bloki treścią i gotowe. Django weźmie szablon bazowy i wypełni jego bloki podanymi przez nas danymi.
A co z duplikacją kodu w news_list.html i category_news_list.html, gdzie mamy identyczny kod listujący wiadomości? Możemy przenieść kod z pętlą do oddzielnego szablonu i użyć taga include do jego załączenia w obu szablonach. Ja stworzyłem news/parts/news_list.html i następnie załączyłem go w szablonach listy:
Kod pętli się nie dubluje dzięki zastosowaniu include.Pliki statyczne
Pliki statyczne to wszystkie pliki frontendowe - CSS, JS, grafiki itp. W Django pliki statyczne dzielą się na dwie grupy - "statyka" i "media". Media to pliki stworzone/przesłane przez użytkowników - np. ikony kategorii. "Statyka" to pliki związane z wyglądem strony (CSS, JS, pliki graficzne) i inne statyczne pliki wykorzystywane w szablonach (np. regulamin jako plik PDF).
Pliki "statyki" umieszczamy w katalogu static w danej aplikacji Django. Można stworzyć oddzielną aplikację Django na podstawowe szablony i pliki, można też np. umieścić je w najważniejszej" aplikacji projektu. W szablonach ścieżka do statyki dostępna jest poprzez zmienną STATIC_URL, a media poprzez MEDIA_URL. Przykład:
Co dalej?
Tematów jest jeszcze ogrom, ale po tym wprowadzeniu powinieneś mieć obraz programowania z Django, tworzenia aplikacji internetowych za jego pomocą. Warto teraz przejrzeć dokumentacje i artykuły poświęcone widokom opartym o klasy, rozbudować nasz przykładowy blog o formularze komentarzy, dodać obsługę nieistniejących newsów/kategorii poprzez rzucanie 404 - braku strony. Można też stworzyć kanał RSS, czy mapę Sitemap za pomocą wbudowanych w Django komponentów. Użyj tego projektu jako poligon doświadczalny.