7. diel - Databáza filmov v Django - Generic Views a Formuláre
V predchádzajúcej lekcii, Databáza filmov v Django - Databáza, sme si vytvorili modely, naučili sa migrovať databázu a pracovať s Django administráciou.
V dnešnom tutoriáli webových aplikácií s frameworkom Django v Pythone sa budeme venovať generic views, pomocou ktorých naučíme projekt Filmová databáza pracovať s databázou.
Úprava súborov Filmovej databázy
Než sa vrhneme do práce, vytvorme si pomocou databázovej administrácie v
databáze niekoľko ďalších filmov a pokojne aj žánrov, aby sme mali
pohľady na čom skúšať. Náš movie_detail() si odstránime z
views.py, odkaz na tento view odstránime aj z urls.py
a nakoniec odstránime celý súbor movie_detail.html zo zložky
mysite/moviebook/templates/moviebook/.
Generic views v Djangu
Generic views sú predpripravené pohľady pre jednoduché akcie, ktoré sa vo webových aplikáciách často používajú. Práve tie využijeme na pridávanie a editáciu záznamov v našej databáze, aby sme nemuseli písať všetko znova.
ListView
Ako prvý generic view si vyskúšame ListView, ktorý nám
vypíše zoznam položiek. V našom prípade si ním samozrejme necháme
vypísať všetky filmy v databáze. Súbor views.py v priečinku
mysite/moviebook/ teraz upravíme do nasledujúcej podoby:
from django.shortcuts import render from django.views import generic from .models import Movie class MovieIndex(generic.ListView): template_name = "moviebook/movie_index.html" # path to the template from the templates folder (can be shared between applications) context_object_name = "movies" # we will call the list of objects in the template under this name # this method gives us a list of movies sorted by the largest id (9,8,7...) def get_queryset(self): return Movie.objects.all().order_by("-id")
Je nám už zrejmé, čo je obsahom pojmu view. Nebudeme teda ďalej používať mix slovenčiny (pohľad) a angličtiny a budeme sa držať konvenčného anglického označenia view.
Popíšme si kód. Najprv treba naimportovať generic views a
samotné modely. View už teraz nie je tvorené obyčajnou metódou, ale triedou
dediacou z generic.ListView, prípadne z iného generického
pohľadu. Keď sa nad tým zamyslíme, je to logické, pretože práve
dedičnosťou sa nám do view dostane predpripravená funkčnosť. Generic view
nastavíme šablónu a ako sa má premenná s jednotlivými prvkami zoznamu v
šablóne volať. Následne definujeme metódu na získanie všetkých filmov,
ktoré si zoradíme od naposledy pridaných po tie najstaršie.
Na tento view si vytvoríme odkaz v súbore urls.py v priečinku
mysite/moviebook/:
from django.urls import path from . import views urlpatterns = [ path("movie_index/", views.MovieIndex.as_view(), name="movie_index"), ]
Šablóna pre ListView
Šablónu pre náš prvý generic view vytvoríme v priečinku
mysite/moviebook/templates/moviebook/ ako nový súbor
movie_index.html s nasledujúcim obsahom:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> {% for movie in movies %} Title: {{ movie.title }} <br> {% endfor %} </body> </html>
Tento súbor ani všetky nasledujúce nezabudnime ako vždy uložiť v kódovaní UTF-8.
Na adrese http://localhost:8000/moviebook/movie_index/ sa nám
po spustení servera zobrazí zoznam všetkých našich existujúcich
filmov:
DetailView
Teraz by bolo dobré vytvoriť si view aj pre detail vybraného filmu. S tým
nám pomôže DetailView, ktorý nám o filme zobrazí všetky
podrobnosti. Na koniec súboru views.py v priečinku
mysite/moviebook/ pridáme:
class CurrentMovie(generic.DetailView): model = Movie template_name = "moviebook/movie_detail.html"
Trieda CurrentMovie je opäť zddedená z generického predka. V
prípade detailu nastavujeme iba model a názov šablóny.
Šablóna pre DetailView
Šablónu pre DetailView vytvoríme v priečinku
mysite/moviebook/templates/moviebook/ ako nový súbor
movie_detail.html, ktorý sme vyššie nastavili.
Všimnime si pomenovanie súborov, kedy je názov zložený z názvu entity, podčiarkovníka a názvu generic view. Tejto praxe sa budeme držať.
Obsah šablóny je nasledujúci:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <h1> {{ movie.title }} </h1> <small> {{ movie.director}} </small> <h3> {{ movie.genre.genre_name }} </h3> </body> </html>
Každý DetailView potrebuje poznať ID/PK
(primárny kľúč) konkrétneho filmu, pre ktorý nám bude zobrazovať všetky
informácie, aby si ho mohol z databázy načítať. Odkaz na film preto bude
obsahovať aj PK konkrétneho filmu. Upravíme preto v priečinku
mysite/moviebook/ súbor urls.py:
from django.urls import path from . import views urlpatterns = [ path("movie_index/", views.MovieIndex.as_view(), name="movie_index"), path("<int:pk>/movie_detail/", views.CurrentMovie.as_view(), name="movie_detail"), ]
Tým sme Django vysvetlili, že keď používateľ zadá URL adresu na detail
filmu, číslo pred ňou je primárny kľúč (ID) tohto filmu.
Teraz odkaz na film pridáme do výpisu filmov, teda do šablóny
movie_index.html. Obyčajný používateľ sa totiž zatiaľ stále
nemá ako dostať na stránku s informáciami o filme. Do odkazu nezadáme
absolútnu adresu, ale použijeme názov URL, ktorý sme v routoch uviedli (v
tomto prípade name="movie_detail"). Ako parameter odovzdáme
ID/PK. URL je takto jednoduchšia a keby sa adresa view niekedy
zmenila, táto zmena sa prejaví bez nutnosti šablónu upraviť. Pridajme teda
odkaz do movie_index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> {% for movie in movies %} <a href="{% url 'movie_detail' movie.id %}"> Title: {{ movie.title }} <br> </a> {% endfor %} </body> </html>
Po znovunačítaní adresy
http://localhost:8000/moviebook/movie_index/ budú už filmy v
zozname ako odkazy:
Po kliknutí na film budeme presmerovaní na detail daného filmu:
Ak však používateľ bude natoľko trúfalý a zadá do URL ID
neexistujúceho objektu, view nám vyhodí Error 404.
Formulár
Filmy teda vieme vypisovať a zobrazovať ich detail. Ale čo film pridať
alebo upraviť? Za týmto účelom si vytvoríme formulár, čo urobíme pomocou
triedy ModelForm. Formulár by sme samozrejme mohli vytvoriť
oldschool cestou len ako čisté HTML, ako sme to robili v kalkulačke, ale
Django tu máme práve preto, aby sme sa naučili, ako si s ním uľahčiť
prácu. Vytvoríme si preto v priečinku mysite/moviebook/ nový
modul forms.py, v ktorom sa bude nachádzať náš formulár:
from django import forms from .models import Movie class MovieForm(forms.ModelForm): class Meta: model = Movie fields = ["title", "director", "genre"]
Ako ďalší krok si (ako zvyčajne) vytvoríme view, ktoré bude stránku s
formulárom obsluhovať. Prejdeme do súboru views.py, kam pridáme
nový import práve na náš formulár:
from django.shortcuts import render from django.views import generic from .models import Movie from .forms import MovieForm # New import # ...
CreateView
Okrem importu na koniec súboru pridáme aj obsluhu formulára, ktorú si
čoskoro vysvetlíme. Použijeme pre ňu generic view CreateView.
Vidíme, ako môžeme z Django prevziať množstvo funkcionality, ktorú by sme
inak museli implementovať sami:
# ... class CreateMovie(generic.edit.CreateView): form_class = MovieForm template_name = "moviebook/create_movie.html" # Method for GET request, only displays the form def get(self, request): form = self.form_class(None) return render(request, self.template_name, {"form": form}) # Method for POST request, checks the form; if it is valid, creates a new movie; if not, displays the form with an error message def post(self, request): form = self.form_class(request.POST) if form.is_valid(): form.save(commit=True) return render(request, self.template_name, {"form": form})
View nastavujeme formulár a šablónu. Ďalej obsahuje dve akcie, metóda
get() formulár iba zobrazuje a metóda post() ho
spracováva v prípade, že už bol odoslaný. Všimnime si, že v oboch
akciách formulár odovzdávame pomocou slovníka do šablóny, aby sme ho tam
mohli vykresliť. Určite by sme sa nemali v metóde post()
zabudnúť opýtať, či bol formulár správne vyplnený. Keďže formulár
vie, aký model spracováva, na uloženie filmu na ňom stačí zavolať len
metódu save() a je hotovo.
Pre nové view a teda novú adresu si ako vždy pridáme route v
urls.py:
from django.urls import path from . import views urlpatterns = [ path("movie_index/", views.MovieIndex.as_view(), name="movie_index"), path("<int:pk>/movie_detail/", views.CurrentMovie.as_view(), name="movie_detail"), path("create_movie/", views.CreateMovie.as_view(), name="new_movie"), ]
Šablóna pre CreateView
Rovnako ako v predchádzajúcich prípadoch si vytvoríme šablónu v novom
súbore create_movie.html. Náš formulár zatiaľ bude veľmi
primitívny:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <form method="POST"> {% csrf_token %} <!-- Django requires authentication against csrf attack --> {{ form }} <input type="submit"> </form> </body> </html>
Výsledný formulár vyzerá takto:
Náš formulár zatiaľ nie je príliš pekný, ale to v budúcej lekcii
zmeníme pomocou django-crispy-forms. Po odoslaní validného
formulára sa vytvorí nový film. Po prechode na
http://localhost:8000/moviebook/movie_index si môžeme
vyskúšať, že sa medzi filmami naozaj zobrazí. Naša aplikácia začína
byť reálne použiteľná 
Zdrojový kód je opäť v archíve pod lekciou.
V nasledujúcej lekcii, Databáza filmov v Django - Crispy forms a Bootstrap, si do svojej aplikácie na evidenciu filmov integrujeme django-crispy-forms a naučíme sa presmerovať z východiskovej adresy na konkrétny pohľad.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 65x (64.16 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python
