IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 7 - Databáze filmů v Django - Generic Views a Formuláře

V minulé lekci, Databáze filmů v Django - Databáze, jsme si vytvořili modely, naučili se migrovat databázi a pracovat s Django administrací.

V dnešním tutoriálu webových aplikací s frameworkem Django v Pythonu se budeme věnovat generic views, pomocí kterých naučíme projekt Filmová databáze pracovat s databází.

Úprava souborů Filmové databáze

Než se vrhneme do práce, vytvořme si pomocí databázové administrace v databázi několik dalších filmů a klidně i žánrů, abychom měli pohledy na čem zkoušet. Náš detail_filmu() si odstraníme z views.py, odkaz na tento view odstraníme také z urls.py a nakonec odstraníme celý soubor detail_filmu.html ze složky mysite/moviebook/templates/moviebook/.

Generic views v Djangu

Generic views jsou předpřipravené pohledy pro jednoduché akce, které se ve webových aplikacích často používají. Právě ty využijeme pro přidávání a editaci záznamů v naší databázi, abychom nemuseli psát vše znovu.

ListView

Jako první generic view si vyzkoušíme ListView, který nám vypíše seznam položek. V našem případě si jím samozřejmě necháme vypsat všechny filmy v databázi. Soubor views.py ve složce mysite/moviebook/ nyní upravíme do následující 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 již zřejmé, co je obsahem pojmu view. Nebudeme tedy dál používat mix češtiny (pohled) a angličtiny a budeme se držet konvenčního anglického označení view.

Popišme si kód. Nejprve je třeba naimportovat generic views a samotné modely. View nyní již není tvořené pouhou metodou, ale třídou dědící z generic.ListView, případně z jiného generického pohledu. Když se nad tím zamyslíme, je to logické, protože právě dědičností se nám do view dostane předpřipravená funkčnost. Generic view nastavíme šablonu a jak se má proměnná s jednotlivými prvky seznamu v šabloně jmenovat. Následně definujeme metodu pro získání všech filmů, které si seřadíme od posledně přidaných po ty nejstarší.

Na tento view si vytvoříme odkaz v souboru urls.py ve složce mysite/moviebook/:

from django.urls import path
from . import views

urlpatterns = [
    path("film_index/", views.FilmIndex.as_view(), name="filmovy_index"),
]

Šablona pro ListView

Šablonu pro náš první generic view vytvoříme ve složce mysite/moviebook/templates/moviebook/ jako nový soubor film_index.html s následujícím obsahem:

<!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 soubor ani všechny následující nezapomeňme jako vždy uložit v kódování UTF-8.

Na adrese http://localhost:8000/moviebook/film_index/ se nám po spuštění serveru zobrazí seznam všech našich stávajících filmů:

localhost:8000/mo­viebook/film_in­dex
localhost:8000/mo­viebook/film_in­dex

DetailView

Nyní by bylo dobré vytvořit si i view pro detail vybraného filmu. K tomu nám pomůže DetailView, který nám o filmu zobrazí veškeré podrobnosti. Na konec souboru views.py ve složce mysite/moviebook/ přidáme:

class CurrentFilm(generic.DetailView):

    model = Film
    template_name = "moviebook/film_detail.html"

Třída CurrentFilm je opět odděděná z generického předka. V případě detailu nastavujeme jen model a název šablony.

Šablona pro DetailView

Šablonu pro DetailView vytvoříme ve složce mysite/moviebook/templates/moviebook/ jako nový soubor film_detail.html, který jsme výše nastavili.

Všimněme si pojmenování souborů, kdy je název složený z názvu entity, podtržítka a názvu generic view. Této praxe se budeme držet.

Obsah šablony je následující:

<!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 potřebuje znát ID/PK (primární klíč) konkrétního filmu, pro který nám bude zobrazovat veškeré informace, aby si jej mohl z databáze načíst. Odkaz na film proto bude obsahovat i PK konkrétního filmu. Upravíme proto ve složce mysite/moviebook/ soubor 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 jsme Django vysvětlili, že když uživatel zadá URL adresu na detail filmu, číslo před ní je primární klíč (ID) tohoto filmu.

Nyní odkaz na film přidáme do výpisu filmů, tedy do šablony film_index.html. Obyčejný uživatel se totiž zatím stále nemá jak dostat na stránku s informacemi o filmu. Do odkazu nezadáme absolutní adresu, ale použijeme název URL, který jsme v routách uvedli (v tomto případě name="filmovy_detail"). Jako parametr předáme ID/PK. URL je takto jednodušší a kdyby se adresa view někdy změnila, tato změna se projeví bez nutnosti šablonu upravit. Přidejme tedy 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čtení adresy http://localhost:8000/moviebook/film_index/ budou již filmy v seznamu jako odkazy:

localhost:8000/mo­viebook/film_in­dex
localhost:8000/mo­viebook/film_in­dex

Po kliknutí na film budeme přesměrováni na detail daného filmu:

localhost:8000/mo­viebook/2/fil­m_detail
localhost:8000/mo­viebook/2/fil­m_detail

Pokud však uživatel bude natolik troufalý a zadá do URL ID neexistujícího objektu, view nám vyhodí Error 404.

Formulář

Filmy tedy umíme vypisovat a zobrazovat jejich detail. Ale co film přidat nebo upravit? Za tímto účelem si vytvoříme formulář, což uděláme pomocí třídy ModelForm. Formulář bychom samozřejmě mohli vytvořit oldschool cestou jen jako čisté HTML, jako jsme to dělali v kalkulačce, ale Django tu máme právě proto, abychom se naučili, jak si s ním ulehčit práci. Vytvoříme si proto ve složce mysite/moviebook/ nový modul forms.py, ve kterém se bude nacházet náš formulář:

from django import forms
from .models import Film

class FilmForm(forms.ModelForm):

    class Meta:
        model = Film
        fields = ["nazev", "rezie", "zanr"]

Jako další krok si (jako už obvykle) vytvoříme view, které bude stránku s formulářem obsluhovat. Přejdeme do souboru views.py, kam přidáme nový import právě na náš formulář:

from django.shortcuts import render
from django.views import generic

from .models import Film
from .forms import FilmForm  # Nový import

# ...

CreateView

Kromě importu na konec souboru přidáme také obsluhu formuláře, kterou si záhy vysvětlíme. Použijeme pro ní generic view CreateView. Vidíme, jak můžeme z Django převzít spoustu funkcionality, kterou bychom jinak museli implementovat 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ář a šablonu. Dále obsahuje dvě akce, metoda get() formulář pouze zobrazuje a metoda post() jej zpracovává v případě, že již byl odeslán. Všimněme si, že v obou akcích formulář předáváme pomocí slovníku do šablony, abychom jej tam mohli vykreslit. Určitě bychom se neměli v metodě post() zapomenout zeptat, zda byl formulář validně vyplněný. Jelikož formulář ví, jaký model zpracovává, pro uložení filmu na něm stačí zavolat jen metodu save() a je hotovo.

Pro nové view a tedy novou adresu si jako vždy přidá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"),
]

Šablona pro CreateView

Vytvoříme si stejně jako v předchozích případech šablonu v novém souboru create_film.html. Náš formulář zatím bude velice primitivní:

<!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ář vypadá takto:

http://127.0.0­.1:8000/movie­book/create_fil­m/
http://127.0.0­.1:8000/movie­book/create_fil­m/

Náš formulář zatím není příliš hezký, ale to v příští lekci změníme za pomoci django-crispy-forms. Po odeslání validního formuláře se vytvoří nový film. Po přechodu na http://localhost:8000/moviebook/film_index si můžeme vyzkoušet, že se mezi filmy opravdu zobrazí. Naše aplikace začíná být reálně použitelná :)

Zdrojový kód je opět v archivu pod lekcí.

V příští lekci, Databáze filmů v Django - Crispy forms a Bootstrap, si do své aplikace na evidenci filmů integrujeme django-crispy-forms a naučíme se přesměrovávat z výchozí adresy na konkrétní pohled.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 138x (133.18 kB)
Aplikace je včetně zdrojových kódů v jazyce Python

 

Předchozí článek
Databáze filmů v Django - Databáze
Všechny články v sekci
Django - Tvorba webů v Pythonu
Přeskočit článek
(nedoporučujeme)
Databáze filmů v Django - Crispy forms a Bootstrap
Článek pro vás napsal MQ .
Avatar
Uživatelské hodnocení:
74 hlasů
Používám hlavně Python a zajímám se o Deep Learning a vše kolem.
Aktivity