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

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

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

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í lekci se budeme věnovat generic views, pomocí kterých s databází naučíme pracovat naší aplikaci.

Generic views

Generic views jsou předpřipravené views 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.

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

ListView

Jako první generic view si vyzkoušíme ListView, které 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 /mysite/moviebook/views.py 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 templatu ze složky templates (je možné sdílet mezi aplikacemi)
    context_object_name = "filmy" # pod tímto jménem budeme volat list objektů v templatu

# tato funkce nám získává list filmů seřazených od největšího id (9,8,7...)
    def get_queryset(self):
        return Film.objects.all().order_by("-id")

Jako první 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íte, 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 /mysite/moviebook/urls.py

from django.urls import path
from . import views

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

Template pro náš první generic view ListView bude v souboru /mysite/moviebook/templates/moviebook/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>

Soubor nezapomeňte jako vždy uložit v kódování UTF-8.

Na adrese http://localhost:8000/moviebook/film_index/ se nám 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 /mysite/moviebook/views.py přidáme:

class CurrentFilmView(generic.DetailView):

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

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

Šablona

Šablonu pro view vytvoříme v /mysite/moviebook/templates/moviebook/film_detail.html, který jsme v detail view výše nastavili. Všimněte si pojmenování souborů, kdy je název složený z názvu entity, podtržítka a názvu generic view. 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>

Uložte v UTF-8.

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 soubor /mysite/moviebook/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.CurrentFilmView.as_view(), name="filmovy_detail"),
]

Tím jsme Dajngo vysvětlili, že když někdo zadá URL adresu na detail filmu, je to číslo před ní primární klíč (ID) tohoto filmu.

Nyní odkaz na film přidáme do výpisu filmů, tedy do šablony /mysite/moviebook/templates/moviebook/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 pohledu 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 opětovném otevření 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 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 nový modul /mysite/moviebook/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"]

Asi vás nepřekvapí, že jako další krok si vytvoříme view, které bude stránku s formulářem obsluhovat. Přejdeme do /mysite/moviebook/views.py, kde přidáme nový import právě na náš formulář:

from django.shortcuts import render, redirect, render_to_response
from django.views import generic

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

# ...

CreateView

Kromě importu na konec souboru přidáme 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 2 akce, get() formulář pouze zobrazuje a post() jej zpracovává v případě, že již byl odeslán. Všimněte si, že v obou akcích formulář předáváme pomocí listu 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 /mysite/moviebook/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.CurrentFilmView.as_view(), name="filmovy_detail"),
    path("create_film/", views.CreateFilm.as_view(), name="novy_film"),
]

Šablona

Vytvoříme si template /mysite/moviebook/templates/moviebook/create_film.html pro náš formulář, který 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>

Uložíme v UTF-8. Výsledný formulář vypadá zatím takto:

Formulář pomocí ModelForm v Django v Pythonu

Náš formulář 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ůžete vyzkoušet, že se mezi filmy opravdu zobrazí. Naše aplikace začíná být reálně použitelná :)

To je pro dnešní lekci vše. Příště bych rád v lekci Databáze filmů v Django - Crispy forms a Bootstrap probral "base template", již zmiňované django-crispy-form a vytvoříme si DB model uživatele.


 

Stáhnout

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

 

 

Článek pro vás napsal MQ .
Avatar
Jak se ti líbí článek?
3 hlasů
Autor je srdcem Pythonista.
Aktivity (3)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!