Dodawanie, edycja, usuwanie czy przeglądanie danych zgromadzonych w bazie
są typowymi czynnościami w aplikacjach internetowych. Utworzony w scenariuszu Czat (cz. 1)
kod ilustruje “ręczną” obsługę żądań GET i POST, w tym tworzenie formularzy,
walidację danych itp. Django zawiera jednak gotowe mechanizmy, których
użycie skraca i ulepsza pracę programisty eliminując potencjalne błędy.
Będziemy rozwijać kod uzyskany po zrealizowaniu punktów 8.1.1 – 8.1.10 scenariusza
Czat (cz. 1). Pobierz więc archiwum
i rozpakuj w katalogu domowym użytkownika. Następnie wydaj polecenia:
Przypominamy, że pracujemy w wirtualnym środowisku Pythona z zainstalowanym frameworkiem
Django, które powinno znajdować się w katalogu pve3. Zobacz w scenariuszu Czat (cz. 1),
jak utworzyć takie środowisko.
Na początku zajmiemy się obsługą użytkowników. Umożliwimy im samodzielne
zakładanie kont w serwisie, logowanie i wylogowywanie się. Inaczej niż w cz. 1
zadania te zrealizujemy za pomocą tzw. widoków wbudowanych opartych na klasach
(ang. class-based generic views).
Na początku pliku czat2/czat/urls.py importujemy formularz tworzenia użytkownika
(UserCreationForm) oraz wbudowany widok przeznaczony do dodawania danych (CreateView):
Na koniec wstawimy link na stronie głównej, a więc uzupełniamy plik index.html:
Plik index.htmlKod nr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- templates/czat/index.html --><html><head></head><body><h1>Witaj w aplikacji Czat!</h1>
{% if user.is_authenticated %}
<p>Jesteś zalogowany jako {{ user.username }}.</p>
{% else %}
<p><ahref="{% url 'czat:rejestruj' %}">Zarejestruj się</a></p>
{% endif %}
</body></html>
Ćwiczenie: dodaj link do strony głównej w szablonie rejestruj.html.
Uruchom aplikację (pythonmanage.pyrunserver) i przetestuj dodawanie użytkowników:
spróbuj wysłać niepełne dane, np. bez hasła; spróbuj dodać dwa razy tego samego użytkownika.
Widać, że z adresami /loguj i /wyloguj wiążemy wbudowane w Django widoki login
i logout importowane z modułu django.contrib.auth.views. Jedynym nowym
parametrem jest next_page, za pomocą którego wskazujemy stronę
wyświetlaną po wylogowaniu (reverse_lazy('czat:index')).
Logowanie wymaga szablonu loguj.html, który tworzymy i zapisujemy w podkatalogu templates/czat:
Musimy jeszcze określić stronę, na którą powinien zostać przekierowany
użytkownik po udanym zalogowaniu. W tym wypadku na końcu pliku czat2/settings.py
definiujemy wartość zmiennej LOGIN_REDIRECT_URL:
Chcemy, by zalogowani użytkownicy mogli przeglądać wiadomości wszystkich użytkowników,
zmieniać, usuwać i dodawać własne. Najprostszy sposób to skorzystanie z
widoków wbudowanych.
Informacja
Django oferuje wbudowane widoki przeznaczone do typowych operacji:
DetailView i ListView – (ang. generic display view) widoki przeznaczone
do prezentowania szczegółów i listy danych;
FormView, CreateView, UpdateView i DeleteView – (ang. generic editing views)
widoki przeznaczone do wyświetlania formularzy ogólnych, w szczególności
służących dodawaniu, uaktualnianiu, usuwaniu obiektów (danych).
Do wyświetlania listy wiadomości użyjemy klasy ListView.
Do pliku urls.py dopisujemy importy:
Zakładamy, że wiadomości mogą oglądać tylko użytkownicy zalogowani. Dlatego
całe wywołanie widoku umieszczamy w funkcji login_required().
W funkcji ListView.as_view() podajemy kolejne parametry
modyfikujące działanie widoków:
model – podajemy model, którego dane zostaną pobrane z bazy;
context_object_name – pozwala zmienić domyślną nazwę (object_list)
listy obiektów przekazanych do szablonu;
paginate_by– pozwala określić ilość obiektów wyświetlanych na stronie.
Na końcu pliku czat2/settings.py określamy adres logowania,
na który przekierowani zostaną niezalogowani użytkownicy, którzy próbowaliby
zobaczyć listę wiadomości:
Potrzebujemy szablonu, którego Django szuka pod domyślną nazwą
<nazwa modelu>_list.html, czyli w naszym przypadku tworzymy plik czat/wiadomosc_list.html:
Kolejne wiadomości odczytujemy i wyświetlamy w pętli przy użyciu tagu {%for%}.
Dostęp do właściwości obiektów umożliwia operator kropki, np.: {{wiadomosc.autor.username}}.
Linki nawigacyjne tworzymy w instrukcji warunkowej {%ifis_paginated%}.
Obiekt page_obj zawiera następujące właściwości:
has_previous – zwraca True, jeżeli jest poprzednia strona;
previous_page_number – numer poprzedniej strony;
next_page_number – numer następnej strony;
number – numer aktualnej strony;
paginator.num_pages – ilość wszystkich stron.
Numer strony do wyświetlenia przekazujemy w zmiennej page adresu URL.
Ćwiczenie: Dodaj link do strony wyświetlającej wiadomości na stronie głównej dla zalogowanych użytkowników.
Zadanie to zrealizujemy wykorzystując widok CreateView. Aby ułatwić
dodawanie wiadomości dostosujemy klasę widoku tak, aby użytkownik
nie musiał wprowadzać pola autor.
Na początek dopiszemy w pliku urls.py skojarzenie adresu URL
wiadomosc/ z wywołaniem klasy CreateView jako funkcji:
Tworzymy klasę opartą na widoku ogólnym (classDodajWiadomosc(CreateView)),
określamy jej podstawowe właściwości i nadpisujemy wybrane metody:
fields – pozwala wskazać pola, które mają znaleźć się na formularzu;
get_initial() – metoda pozwala ustawić domyślne wartości dla wybranych pól.
Wykorzystujemy ją do zainicjowania pola data_pub aktualna datą:
initial['data_pub']=timezone.now().
get_context_data() – metoda pozwala przekazać do szablonu dodatkowe dane,
w tym wypadku jest to lista wszystkich wiadomości: context['wiadomosci']=Wiadomosc.objects.all().
form_valid() – metoda, która sprawdza poprawność przesłanych danych i zapisuje je w bazie:
wiadomosc=form.save(commit=False) – tworzymy obiekt wiadomości, ale go nie zapisujemy;
wiadomosc.autor=self.request.user – uzupełniamy dane autora;
wiadomosc.save() – zapisujemy obiekt;
messages.success(self.request,"Dodanowiadomość!") – przygotowujemy komunikat,
który wyświetlony zostanie po dodaniu wiadomości.
Domyślny szablon dodawania danych nazywa się <nazwa modelu>_form.html. W nowym pliku
wstawiamy poniższą treść i zapisujemy pod nazwą templates/czat/wiadomosc_form.html:
W szablonie templates/czat/wiadomosc_list.html wstawimy jeszcze po nagłówku
<h1> kod wyświetlający komunikaty:
Plik wiadomosc_list.htmlKod nr
6
7
8
9
10
11
12
{% if messages %}
<ul>
{% for komunikat in messages %}
<li>{{ komunikat|capfirst }}</li>
{% endfor %}
</ul>
{% endif %}
Ostrzeżenie
W pliku czat/models.py trzeba usunąć parametr auto_now_add=True
z definicji pola data_pub, aby użytkownik mógł modyfikować datę
dodania wiadomości w formularzu.
Ćwiczenie: Jak zwykle, umieść link do dodawanie wiadomości na stronie głównej.
Widok pozwalający na edycję wiadomości i jej aktualizację dostępny będzie
pod adresem /edytuj/id_wiadomości, gdzie id_wiadomosci będzie identyfikatorem
obiektu do zaktualizowania. Zaczniemy od uzupełnienia pliku urls.py:
Nowością w powyższym kodzie są wyrażenia regularne definiujące adresy z dodatkowym
parametrem, np. r'^edytuj/(?P<pk>\d+)/'. Część /(?P<pk>\d+) oznacza,
że oczekujemy 1 lub więcej cyfr (\d+), które zostaną zapisane w zmiennej o nazwie
pk (?P<pk>) – nazwa jest tu skrótem od ang. wyrażenia primary key,
co znaczy “klucz główny”. Zmienna ta zawierać będzie identyfikator wiadomości
i dostępna będzie w klasie widoku, który obsłuży edycję wiadomości.
Na początku pliku views.py importujemy więc potrzebny widok:
Plik views.pyKod nr
10
fromdjango.views.generic.editimportUpdateView
Dalej tworzymy klasę EdytujWiadomosc, która dziedziczy, czyli dostosowuje wbudowany
widok UpdateView:
Najważniejsza jest tu metoda get_object(), która pobiera i zwraca wskazaną przez
identyfikator w zmiennej pk wiadomość: wiadomosc=Wiadomosc.objects.get(id=self.kwargs['pk']).
Omawianą już metodę get_context_data() wykorzystujemy, aby przekazać
do szablonu listę wiadomości, ale tylko zalogowanego użytkownika
(context['wiadomosci']=Wiadomosc.objects.filter(autor=self.request.user)).
Właściwości model, context_object_name, template_name i success_url
wyjaśniliśmy wcześniej. Jak widać, do edycji wiadomości można wykorzystać ten sam szablon,
którego użyliśmy podczas dodawania.
Formularz jednak dostosujemy. Wykorzystamy właściwość form_class,
której przypisujemy utworzoną w nowym pliku forms.py klasę zmieniającą
domyślne ustawienia:
Klasa EdytujWiadomoscForm oparta jest na wbudowanej klasie ModelForm.
Właściwości formularza określamy w podklasie Meta:
model – oznacza to samo co w widokach, czyli model, dla którego tworzony jest formularz;
fields – to samo co w widokach, lista pól do wyświetlenia;
exclude – opcjonalnie lista pól do pominięcia;
widgets – słownik, którego klucze oznaczają pola danych, a ich wartości
odpowiadające im w formularzach HTML typy pól i ich właściwości, np. rozmiar.
Żeby przetestować aktualizowanie wiadomości, w szablonie wiadomosc_list.html
trzeba wygenerować linki Edytuj dla wiadomości utworzonych przez zalogowanego użytkownika.
Wstaw w odpowiednie miejsce szablonu, tzn po tagu wyświetlającym tekst wiadomości
({{wiadomosc.tekst}}) poniższy kod:
Usuwanie danych realizujemy za pomocą widoku DeleteView, który importujemy
na początku pliku urls.py:
Plik urls.pyKod nr
13
fromdjango.views.genericimportDeleteView
Podobnie, jak w przypadku edycji, usuwanie powiążemy z adresem URL zawierającym
identyfikator wiadomości /usun/id_wiadomości. W pliku urls.py dopisujemy:
Warto zwrócić uwagę, że podobnie jak w przypadku listy wiadomości, o ile wystarcza nam
domyślna funkcjonalność widoku wbudowanego, nie musimy niczego implementować w pliku views.py.
Domyślny szablon dla tego widoku przyjmuje nazwę <nazwa-modelu>_confirm_delete.html,
dlatego uprościliśmy jego nazwę we właściwości template_name. Tworzymy więc plik
wiadomosc_usun.html:
Tag {{object}} zostanie zastąpiony treścią wiadomości zwróconą przez funkcję
“autoprezentacji” __str__() modelu.
Ćwiczenie: Wstaw link “Usuń” (•<ahref="{%url'czat:usun'wiadomosc.id%}">Usuń</a>) za linkiem “Edytuj” w szablonach wyświetlających listę wiadomości.