Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
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í.

7. diel - Databázy filmov v Django - Generic Views a Formuláre

V minulej lekcii, Databázy filmov v Django - Databáza , sme si vytvorili modely, naučili sa migrovať databázu a pracovať s Django administráciou. V dnešnej lekcii sa budeme venovať generic views, pomocou ktorých s databázou naučíme pracovať našej aplikácii.

Generic views

Generic views sú predpripravené views pre jednoduché akcie, ktoré sa vo webových aplikáciách často používajú. Práve tie využijeme pre pridávanie a editáciu záznamov v našej databáze, aby sme nemuseli písať všetko znova.

Než sa na ne vrhneme, vytvorte si pomocou databázové administrácie v databáze niekoľko ďalších filmov a pokojne aj žánrov, aby sme mali views na čom skúšať. Náš index view si odstránime z views.py, odkaz na tento view odstránime z urls.py a nakoniec tiež odstránime súbor /mysite/moviebook/templates/moviebook/index.html.

ListView

Ako prvý generic view si vyskúšame ListView, ktoré 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 /mysite/moviebook/views.py 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 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")

Ako prvé je potrebné naimportovať generic views a samotné modely. View teraz už nie je tvorené obyčajnou metódou, ale triedou dedičov z generic.ListView, prípadne z iného generického pohľadu. Keď sa nad tým zamyslíte, 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 vymenovať. Následne definujeme metódu pre získanie všetkých filmov, ktoré si zoradíme od posledne pridaných po tie najstaršie.

Na tento view si vytvorí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 pre náš prvý generic view ListView bude v súbore /mysite/moviebook/templates/moviebook/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>

Súbor nezabudnite ako vždy uložiť v kódovaní UTF-8.

Na adrese http://localhost:8000/moviebook/film_index/ sa nám zobrazí zoznam všetkých našich existujúcich filmov:

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

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 zobrazia všetky podrobnosti. Na koniec /mysite/moviebook/views.py pridáme:

class CurrentFilmView(generic.DetailView):

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

View je opäť trieda, odděděná z generického predka. V prípade detaile nastavujeme len model a názov šablóny.

Šablóna

Šablónu pre view vytvoríme v /mysite/moviebook/templates/moviebook/film_detail.html, ktorý sme v detail view vyššie nastavili. Všimnite si pomenovanie súborov, kedy je názov zložený z názvu entity, podčiarknutia a názvu generic view. 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>

Uložte v UTF-8.

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 súbor /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 sme Dajngo vysvetlili, že keď niekto zadá URL adresu na detail filmu, je to číslo pred ňou primárny kľúč (ID) tohto filmu.

Teraz odkaz na film pridáme do výpisu filmov, teda do šablóny /mysite/moviebook/templates/moviebook/film_index.html. Obyčajný uží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šie a keby sa adresa pohľadu 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 opätovnom otvorení adresy http://localhost:8000/moviebook/film_index/ budú už filmy v zozname ako odkazy:

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

Po kliknutí na film budeme presmerovaný na detail daného filmu:

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

Ak 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 vieme vypisovať a zobrazovať ich detail. Ale čo film pridať alebo upraviť? Na tento účel 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 nový modul /mysite/moviebook/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"]

Asi vás neprekvapí, že ako ďalší krok si vytvoríme view, ktoré bude stránku s formulárom obsluhovať. Prejdeme do /mysite/moviebook/views.py, kde pridáme nový import práve na náš formulár:

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

Okrem importu na koniec súboru pridáme obsluhu formulára, ktorú si vzápätí vysvetlíme. Použijeme pre ňu generic view CreateView. Vidíme ako môžeme z Django prevziať veľa 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 2 akcie, get() formulár iba zobrazuje a post() ho spracováva v prípade, že už bol odoslaný. Všimnite si, že v oboch akciách formulár odovzdávame pomocou listu 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 validný vyplnený. Keďže formulár vie aký model spracúva, pre uloženie filmu na ňom stačí zavolať len metódu save() a je hotovo.

Pre nových view a teda novú adresu si ako vždy pridáme route 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"),
]

Šablóna

Vytvoríme si template /mysite/moviebook/templates/moviebook/create_film.html pre náš formulár, ktorý bude veľmi primitívne.

<!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ár vyzerá zatiaľ takto:

Formulár pomocou ModelForm v Django v Pythone - Tvorba webov v Django frameworku pre Python

Náš formulár nie je príliš pekný, ale to v nasledujúcej lekcii zmeníme za pomoci django-crispy-forms. Po odoslaní validného formulára sa vytvorí nový film. Po prechode na http://localhost:8000/moviebook/film_index si môžete vyskúšať, že sa medzi filmami naozaj zobrazí. Naša aplikácia začína byť reálne použiteľná :)

To je pre dnešné lekciu všetko. Nabudúce by som rád v lekcii Databázy filmov v Django - Crispy forms a Bootstrap prebral "base template", už zmieňované django-crispy-form a vytvoríme si DB model používateľa.


 

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é 135x (133.18 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python

 

Predchádzajúci článok
Databázy filmov v Django - Databáza
Všetky články v sekcii
Tvorba webov v Django frameworku pre Python
Preskočiť článok
(neodporúčame)
Databázy filmov v Django - Crispy forms a Bootstrap
Článok pre vás napísal MQ .
Avatar
Užívateľské hodnotenie:
1 hlasov
Používám hlavně Python a zajímám se o Deep Learning a vše kolem.
Aktivity