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áš detail_filmu()
si odstránime z
views.py
, odkaz na tento view odstránime aj z urls.py
a nakoniec odstránime celý súbor detail_filmu.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 Film class FilmIndex(generic.ListView): template_name = "moviebook/film_index.html" # cesta k šabloně ze složky templates (je možné sdílet mezi aplikacemi) context_object_name = "filmy" # pod tímto jménem budeme volat seznam objektů v šabloně # tato metoda nám získává seznam filmů seřazených od největšího id (9,8,7...) def get_queryset(self): return Film.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("film_index/", views.FilmIndex.as_view(), name="filmovy_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
film_index.html
s nasledujúcim obsahom:
<!DOCTYPE html> <html lang="cs"> <head> <meta charset="UTF-8"> </head> <body> {% for film in filmy %} Název: {{ film.nazev }} <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/film_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 CurrentFilm(generic.DetailView): model = Film template_name = "moviebook/film_detail.html"
Trieda CurrentFilm
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
film_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="cs"> <head> <meta charset="UTF-8"> </head> <body> <h1> {{ film.nazev }} </h1> <small> {{ film.rezie }} </small> <h3> {{ film.zanr.nazev_zanru }} </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("film_index/", views.FilmIndex.as_view(), name="filmovy_index"), path("<int:pk>/film_detail/", views.CurrentFilm.as_view(), name="filmovy_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
film_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="filmovy_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 film_index.html
:
<!DOCTYPE html> <html lang="cs"> <head> <meta charset="UTF-8"> </head> <body> {% for film in filmy %} <a href="{% url 'filmovy_detail' film.id %}"> Název: {{ film.nazev }} <br> </a> {% endfor %} </body> </html>
Po znovunačítaní adresy
http://localhost:8000/moviebook/film_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 Film class FilmForm(forms.ModelForm): class Meta: model = Film fields = ["nazev", "rezie", "zanr"]
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 Film from .forms import FilmForm # Nový 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 CreateFilm(generic.edit.CreateView): form_class = FilmForm template_name = "moviebook/create_film.html" # Metoda pro GET request, zobrazí pouze formulář def get(self, request): form = self.form_class(None) return render(request, self.template_name, {"form": form}) # Metoda pro POST request, zkontroluje formulář; pokud je validní, vytvoří nový film; pokud ne, zobrazí formulář s chybovou hláškou 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("film_index/", views.FilmIndex.as_view(), name="filmovy_index"), path("<int:pk>/film_detail/", views.CurrentFilm.as_view(), name="filmovy_detail"), path("create_film/", views.CreateFilm.as_view(), name="novy_film"), ]
Šablóna pre CreateView
Vytvoríme si rovnako ako v predchádzajúcich prípadoch šablónu v novom
súbore create_film.html
. Náš formulár zatiaľ bude veľmi
primitívny:
<!DOCTYPE html> <html lang="cs"> <head> <meta charset="UTF-8"> </head> <body> <form method="POST"> {% csrf_token %} <!-- Django požaduje ověření proti útoku csrf --> {{ 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/film_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é 164x (133.18 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python