7. diel - Databáza filmov v Django - Generic Views a Formuláre
V minulej 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 teraz už 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 aj view pre detail vybraného filmu. K tomu
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äť oddedená 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 routách 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:
Pokiaľ však uží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 už obvykle) 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 validne 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 routu 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
Vytvoríme si rovnako ako v predchádzajúcich prípadoch š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 presmerovávať 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é 3x (53.78 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python