Django: Prezentace dat

Projekt jsme na konci minulého dílu zanechali ve stavu, ve kterém správci mohou pohodlně upravovat data z našich databázových modelů. Nyní se naučíme, jak tato data prezentovat návštěvníkům webu.
Seriál: Hrajeme si s Djangem (16 dílů)
- Django: Úvod a instalace 14. 8. 2009
- Django: Nastavení projektu a první pokusy 21. 8. 2009
- Django: Databázový model 28. 8. 2009
- Django: Databázový model podruhé 4. 9. 2009
- Django: Administrace 11. 9. 2009
- Django: Prezentace dat 18. 9. 2009
- Django: Prezentace dat podruhé 25. 9. 2009
- Django: Zpracovávání formulářů 2. 10. 2009
- Django: Autentizace a autorizace 9. 10. 2009
- Django: Nahrávání souborů 16. 10. 2009
- Django: Zabudované aplikace 23. 10. 2009
- Django: Rozšiřování možností Djanga 30. 10. 2009
- Django: Internacionalizace 6. 11. 2009
- Django: Nasazování projektu 13. 11. 2009
- Django: Kešování a škálování 20. 11. 2009
- Django: Závěr 27. 11. 2009
Nálepky:
Pod pojmem prezentace dat si můžeme představit spojení pohledu a šablony, při kterém zpracováváme data a zobrazujeme je ve vhodné formě uživatelům. Nejprve si ukážeme několik důležitých vlastností šablonovacího systému.
Strukturování šablon
Když jsem kdysi dávno začal s vytvářením HTML stránek a neuměl pořádně programovat v žádném jazyce, nejhorší ze všeho pro mě bylo zamezit opakování základního kódu, např. obsahu značky <head>
, navigace nebo patičky. Jakákoliv změna na stránkách znamenala otevřít všechny „postižené“ soubory a opravit opakující se kusy HTML kódu. Tehdy jsem na to použil rámy, což se časem ukázalo jako naprostý krok vedle. Teď můžu v Djangu stejný problém jednoduše vyřešit použitím značek šablonovacího systému {% block %}
a {% extends %}
.
Princip si ukážeme na příkladu — nejprve si vytvoříme základní šablonu pro web videopůjčoven. Tento soubor bývá zvykem pojmenovávat base.html
a je potřeba ho uložit do adresáře templates
:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>{% block title %}Videopůjčovny s. r. o.{% endblock %}</title> <link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" type="text/css"> </head> <body> <div id="header">Videopůjčovny s. r. o.</div> <div id="menu"> <ul> <li><a href="/">Titulní strana</a></li> <li><a href="/provozovny/">Provozovny</a></li> <li><a href="/nabidka/">Nabídka titulů</a></li> <li><a href="/kontakt/">Kontakt</a></li> <li><a href="/pro_cleny/">Pro členy</a></li> </ul> </div> <div id="content">{% block content %}{% endblock %}</div> </body> </html>
Pomocí značky {% block %}
si označíme místa, kam se budou vkládat bloky kódu pro jednotlivé stránky. V našem případě to je titulek stránky (title
) a její obsah (content
). Text uvedený uvnitř značek v titulku je výchozí text bloku. Na začátku šablony je též uvedena proměnná {{ MEDIA_URL }}
, která obsahuje cestu ke statických souborům. Poskytuje nám ji takzvaný kontextový procesor django.core.context_processors.media
. Kontextové procesory se využívají v situacích, když potřebujeme dostat do více šablon společné proměnné.
Dále si vytvoříme šablonu pro titulní stranu. Ta využije (rozšíří) základní šablonu a přepíše bloky svým vlastním obsahem. Pojmenujeme ji třeba front_page.html
a uložíme ji také do adresáře templates
:
{% extends "base.html" %} {% block content %} <h1>Dobrý den!</h1> <p>Vítáme vás na webu naší sítě poboček videopůjčoven.</p> {% endblock %}
Na prvním řádku jsme pomocí značky {% extends %}
uvedli, že chceme rozšířit šablonu base.html
. V bloku title
jsme nechali výchozí text, obsah bloku content
byl nahrazen za uvítací blábol. Podobně to budeme dělat i u ostatních šablon.
Generické pohledy
Nejlepší kód je ten, který nemusíme psát. To je důvod, proč nám tvůrci Djanga dali k dispozici několik pohledů, jež dělají naprosto obecné věci — kupříkladu přidání, úpravu nebo zobrazení objektu, a proto se jim říká generické pohledy. Můžeme je nalézt v modulu django.views.generic
a zkusíme si použít nejjednodušší z nich, simple.direct_to_template
, který pouze zobrazí šablonu.
Tento pohled stačí přidat mezi URL (do souboru urls.py
v adresáři projektu) a jako parametr poskytnout slovník obsahující klíč template
:
urlpatterns += patterns('', (r'^admin/', include(admin.site.urls)), # Django 1.0: (r'^admin/(.*)', admin.site.root), (r'^$', 'django.views.generic.simple.direct_to_template', {'template': 'front_page.html'}), )
Když nastartujeme vývojový server (python manage.py runserver
) a přejdeme na adresu http://127.0.0.1:8000/, můžeme vidět titulní stranu webu videopůjčoven:
Místo generického pohledu jsme si v souboru video_store/views.py
mohli vytvořit takovou funkci:
from django.shortcuts import render_to_response from django.template import RequestContext def front_page(request): return render_to_response('front_page.html', {}, context_instance=RequestContext(request))
Jediné co je tu nové, je zavolání funkce RequestContext(request)
, což nám zpřístupní výchozí kontextové procesory, abychom mohli v šabloně využít proměnnou {{ MEDIA_URL }}
. Tento pohled bychom museli stejně přidat do URL, takže používání generických pohledů je mnohem úspornější a elegantnější. Proto si vyzkoušíme použít ještě další, na výpis provozoven. Opět si nejdříve vytvoříme šablonu (templates/stores.html
):
{% extends "base.html" %} {% block content %} <h1>{% block title %}Provozovny{% endblock %}</h1> {% for object in object_list %} <h2>{{ object.store }}</h2> <ul class="store"> <li>{{ object.address }}</li> <li>{{ object.city }}</li> <li>{{ object.postal_code }}</li> {% if object.email %} <li><a href="mailto:{{ object.email }}">{{ object.email }}</a></li> {% endif %} </ul> {% if object.description %} <p>{{ object.description }}</p> {% endif %} {% endfor %} {% endblock %}
Především je tu použit jednoduchý trik, který nám zobrazí v titulku stránky stejný text jako v nadpisu, aniž bychom ho museli psát dvakrát. Dále zde můžeme vidět dvě nové značky, {% for %}
a {% if %}
. První se podobá for cyklu z Pythonu, do proměnné object
přiřadí aktuální prvek ze seznamu object_list
. Druhá značka je hodně podobná pythonovému větvení if, až na to, že nepodporuje větev elif
.
object_list
bude obsahovat seznam provozoven. Výchozí pojmenování této proměnné je možné změnit, podobně jako další parametry, viz dokumentaci.V tomto kódu tedy vypíšeme postupně všechny provozovny a jejich adresy. Pokud je zadána e-mailová adresa, vypíšeme i tu. V opravdovém projektu bych se ji snažil nějakým způsobem ochránit před spamery, třeba pomocí JavaScriptu. Jestliže je u pobočky vyplněný popis, vypíšeme ho také. Znova budeme muset provázat šablonu přes generický pohled s adresou (soubor urls.py
), tentokrát je to trochu složitější, protože musíme specifikovat i výběr dat:
from hrajeme_si.video_store.models import Store stores = { 'queryset': Store.objects.all(), 'template_name': 'stores.html', } urlpatterns += patterns('', (r'^admin/', include(admin.site.urls)), # Django 1.0: (r'^admin/(.*)', admin.site.root), (r'^$', 'django.views.generic.simple.direct_to_template', {'template': 'front_page.html'}), (r'^provozovny/$', 'django.views.generic.list_detail.object_list', stores), )
Z důvodů zpřehlednění jsem si definoval proměnnou stores
, místo toho, abych slovník vkládal přímo do parametru. Generický pohled list_detail.object_list
požaduje klíč queryset
, což je klasický QuerySet
— vybrali jsme všechny záznamy z tabulky modelu Store
. Změna oproti předchozímu generickému pohledu je v tom, že se klíč s názvem šablony nejmenuje template
, ale template_name
. Výsledek našeho snažení vypadá takto:
Pro úplnost si ještě ukážeme, jak by to vypadalo bez použití generického pohledu:
from django.shortcuts import render_to_response from django.template import RequestContext from hrajeme_si.video_store.models import Store def stores(request): return render_to_response('stores.html', {'object_list': Store.objects.all()}, context_instance=RequestContext(request))
Generické pohledy doporučuji používat všude kde to jen jde, vyhnete se tak jednotvárnému opakování kódu. Jedná se o jednoduché výpisy položek, jejich kategorizace podle data, přesměrování stránek a základní práci s formuláři. K tomu se dostaneme v pozdějších dílech seriálu.
Související odkazy
- Šablonovací systém a generické pohledy na Djangoproject.com
- Čtvrtá a jedenáctá kapitola v The Definitive Guide to Django
- Ukázkový příklad ke stažení.
V příštím díle navážeme na toto téma a zkusíme si vytvořit složitější pohledy.
Tak přemýšlím, pro koho tyhle články vlastně jsou… Kdybych základy Djanga dopředu neznal, čuměl bych na to jak tele na vrata. Protože je ale znám, nedovídám se tu nic nového.
Clanky by mely seznamit zacatecniky se zakladnimi vlastnosti Djanga.
Pokud Vam pripada jejich forma spatna, muzete obsah ovlivnit. Kazdy tyden Pavel Dvorak na IRC kanalu #django-cs (http://botland.oebfare.com/…r/django-cs/) vystavi dalsi dil serialu a ceka na pripominky z komunity. Budeme radi, kdyz se do diskuze zapojite a posunete kvalitu clanku vys.
Není to pro začátečníka moc chaotické? Jsem si vědom, že každý se učí jinak, ale možná by bylo lepší nejdřív stručně vysvětlit princip, pak příklad použití a potom ukázku kódu… Z trochou nadsázky: tady na mě nejdřív vychrlí nějaké divné značky, pak reálný příklad rovnou zmixovaný s generic views a nakonec z kontextu snad pochopím, že django má šablonovací systém a že jsme jej právě použili. Snaha o stručnost…?
Diky za reakci.
Zkuste po nedeli sledovat zminovane IRC a pridejte svou trosku do mlyna behem pripominkovani dalsiho dilu. Cim vice oci to uvidi a vyjadri svuj nazor, tim bude serial na Zdrojaku kvalitnejsi.
Zdá se mi, že jste pozorně nečetl první díly seriálu, protože princip MTV a šablon jsem nakousl už v prvním a druhém dílu. Možná ne každému vyhovuje, že se v každém díle zabývám něčím jiným a takříkajíc skáču od tématu k tématu, ale rozhodně si dávám pozor na to, abych nepoužil nějakou věc, kterou jsem předtím nezmínil.
Co se týče zaměření, snažím se ukázat základní principy tohoto frameworku a přiblížit jej webovým vývojářům, kteří zatím neměli možnost něco takového používat, ale mají zkušenosti s budováním webových aplikací jinak (např. v čistém Pythonu nebo v PHP). Se stručností máte pravdu, bohužel není v mých silách popsat naprosto všechno – proto vždy přidávám na konec dílu několik souvisejících odkazů, kde si případný zájemce může dané téma nastudovat podrobněji.
Ja jsem pripad uvedeny v druhem odstavci (php a drupal, predtim jsem si napsal vlastni maly cms), a forma clanku mi naprosto vyhovuje – zadne dlouhe zdrzovani, ukazka z realneho sveta, hodne kodu, a z uz uverejnenych par dilu by sel postavit maly editovatelny web… Za sebe tleskam a dekuji, behem par desitek minut jsem si udelal dobrou predstavu k cemu je Django dobre.
napriklad pre mna ;)
No pro tebe urcite ne.
Pokud mate radi Django, ale preferujete Ruby pred Pythonem, muzete se podivat na Rango, ktere je Djangem inspirovane. Napriklad dnes zminovana template inheritance je v Rangu obsazena take (pokud se nemylim, je Rango jediny Ruby framework ktery ji implementuje, jinde jsou ponekud primitivni layout + view).
Jinak je Rango velmi lightweight, snazi se byt as agnostic as possible (bude funguje s libovolnym ORM, template engine etc), plne postavene na Racku, ktery na rozdil od vetsiny frameworku nijak nezakryva, ale naopak vybizi k jeho intenzivnimu pouzivani. Duraz kladu na dobrou dokumentaci (pracuje se na ni), 100% test coverage (opet in progress) a na to, aby to hlavne fungovalo a nikomu to do niceho blbe nekecalo (tj. convention over configuration ano, ale nesmi to byt na ukor konfigurovatelnosti).
Podotykam ze je ve fazi intenzivniho vyvoje a ne vse funguje jak by melo, ne vse je zdokumentovane a ne vse je podporovane. Zacatkem noveho roku ocekavam finalni verzi 1.0.
– Source: http://github.com/botanicus/rango
– Dokumentace: http://wiki.github.com/botanicus/rango
PS: kdyby to treba nekoho zaujalo a chtel pomoct s vyvojem, muzete forknout na GitHubu pripadne commit access davam za prvni prijaty patch.
Nechcete o tom napsat článek, nebo aspoň zprávičku? Ozvěte se na redakce@zdrojak.cz Díky.
Dekuji za nabidku Martine, clanek urcite zvazim, ale nejdrive chci aby to bylo stabilni a zdokumentovane, takze nejdrive nekdy zacatkem pristiho roku. Zpravicku napisu, nejdriv chci ale udelat tutorial a nejaky screencast aby zajemci meli vubec kde zacit.
Po vytvoření souboru admin.py je nutné restartovat vývojový server (python manage.py runserver), jinak si server souboru nevšimne. (django 1.1.1)
Zkusil jsem všechno možné, včetně odhlášení a přihlášení, stažení kompletní sbalené ukázky, čtení jiné dokumentace, všechno marné.
Kromě tohoto je popis od počátku kurzu naprosto dostatečný, krásně jednoduchý a přehledný.
Děkuji.
Promiňte. Komentář patřil k minulému dílu.
Nejprve bych chtel podekovat za „serial“, je velmmi pekne zpracovany a krasne se podle neho uci.
Nicmene se mi nedari rozchodit generecke pohledy a chtel bych se zeptat, jestli to muze mit neco spolecneho s tim, ze jedu pod win 7? Dekuji za odpoved.
Díky za pochvalu. S Windows 7 nemám zkušenosti, ale myslím si, že by se Django mělo na všech platformách chovat stejně. Vypisuje to nějakou chybovou hlášku? Co se stane, když do příkazové řádky Pythonu napíšete příkaz
from django.views.generic.simple import direct_to_template
?Podle me je clanek moc dobre napsany, lepsi cesky clanek na netu urcite nenajdete. Ja jsem si podle tohoto udelal kompletni administracni rozhrani i se strankama behem 3 dnu. A s Pythonem jsem pred tim nemel zadne zkusenosti;-) Je jasne, ze ten kdo se neorientuje ve webovych technologii to nepochopi napoprve. Ovsem to je ve vsech oborech stejne;-)