Django: Zpracovávání formulářů
Pomocí formulářů uživatelé zadávají data do aplikace. Manuální zpracovávání formulářů ale bývá pro programátory hodně otravné. Django naštěstí umožňuje formuláře generovat a zpracovávat, což programátorům usnadňuje život. V článku se na zpracování formulářů v Djangu podíváme podrobněji.
Seriál Hrajeme si s Djangem
- Django: Prezentace dat
- Django: Prezentace dat podruhé
- Django: Zpracovávání formulářů
- Django: Autentizace a autorizace
- Django: Nahrávání souborů
Práce s formulářem by měla být pro uživatele co nejpříjemnější. Doporučuje se proto nepřehánět stylování prvků formuláře, aby to nevedlo ke zmatení. Ideální je ponechat výchozí styl systému. Také by se uživateli při špatně zadaném vstupu mělo zobrazit, kde přesně udělal chybu a jak ji má napravit. V takovém případě nesmí dojít k vymazání zadaných hodnot z formuláře.
Kontaktní formulář
Po několika letech vytváření webů jsem si všiml, že zadavatelé firemních webových stránek mají v oblibě kontaktní formuláře. Do takového formuláře návštěvník vyplní své osobní údaje a požadavek. Po zpracování formuláře se odešle jeho obsah e-mailem. Osobně jsem smysl této funkce moc nepochopil, ale na ukázku práce s formuláři se nám to hodí.
Specifikace formulářů v Djangu se v mnohém podobá databázovým modelům. Později si předvedeme, jak z modelu automaticky generovat formuláře, ale zatím nám bude stačit vytvořit jednoduchý formulář. Vytvoříme si nový soubor video_store/forms.py a do něj napíšeme následující kód:
# coding: utf-8
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(label='Jméno', max_length=100, initial='Anonym')
email = forms.EmailField(label='E-mail', required=False)
phone = forms.CharField(label='Telefon', max_length=20, required=False)
reaction = forms.BooleanField(label='Chci dostat odpověď', required=False)
text = forms.CharField(label='Zpráva', widget=forms.Textarea, help_text='Sem napište svou připomínku nebo dotaz.')
Můžeme si všimnout, že jsme odvodili náš formulář z třídy django.forms.Form. Atributy této nové třídy se podobají atributům databázových modelů, jenom používají trochu jiné parametry. Místo parametru verbose_name, který určuje popisek atributu, tu máme parametr label. Parametr max_length má stejný význam jako u modelů — je to nejvyšší povolený počet znaků, který uživatel může zadat. Také parametr initial se podobá modelovému parametru default, jedná se tedy o předvyplněnou (výchozí) hodnotu atributu. Parametr required má opačný význam než parametr blank, vyskytující se u modelů. Pokud se mu přiřadí hodnota False, znamená to, že je atribut nepovinný, což u modelů představuju hodnote True. Parametr help_text je nápovědný text, který se uživateli zobrazí u políčka formuláře. A parametr widget určuje použitý formulářový prvek. V tomto případě se místo výchozí značky <input type="text"> při generování použije značka <textarea>. Oficiální dokumentace obsahuje přehled všech formulářových prvků a všech druhů formulářových políček.
Když jsme si určili formulář, můžeme si zkusit z něj vygenerovat příslušný HTML kód. Existuje několik metod, které to zvládnou (z důvodů zachování přehlednosti je výpis zkrácen):
>>> from hrajeme_si.video_store.forms import ContactForm
>>> form = ContactForm()
>>> form.as_p()
u'<p><label for="id_name">Jméno:</label> <input id="id_name" type="text" name="name" value="Anonym" maxlength="100" /></p>…'
>>> form.as_ul()
u'<li><label for="id_name">Jméno:</label> <input id="id_name" type="text" name="name" value="Anonym" maxlength="100" /></li>…'
>>> form.as_table()
u'<tr><th><label for="id_name">Jméno:</label></th><td><input id="id_name" type="text" name="name" value="Anonym" maxlength="100" /></td></tr>…'
Tyto tři metody umí vytvořit formulář pomocí odstavců, seznamu a tabulky. Stačilo by příslušnou metodu zavolat na vhodném místě v šabloně (to se dělá např. použitím značky {{ form.as_table }}). Ale co když požadujeme větší kontrolu nad výstupním kódem? Můžeme si vytvořit vlastní šablonu, která bude pomocí cyklu for postupně procházet jednotlivá formulářová políčka a určovat výstupní formát. Takovou šablonu si napíšeme a uložíme do souboru templates/form.html:
{% for f in form %}
{% if f.errors %}
<tr>
<td colspan="2">{{ f.errors }}</td>
</tr>
{% endif %}
<tr>
<th{% if f.field.required %} class="required"{% endif %}>
<label for="id_{{ f.name }}">{{ f.label }}</label>
</th>
<td>{{ f }}</td>
</tr>
{% if f.help_text %}
<tr>
<td></td>
<td class="help_text">{{ f.help_text }}</td>
</tr>
{% endif %}
{% endfor %}
Výstup je podobný metodě as_table, ale máme možnost ho v případě potřeby jednoduše měnit. Na druhém až šestém řádku zobrazíme uživateli chybové hlášky, pokud vyplnil do formuláře něco špatně. Osmý až třináctý řádek generuje samotnou kolonku formuláře i s popiskem. Jestliže je popisek potřeba vyplnit, aplikuje se na něj kaskádová třída required, což uživateli může pomoct s orientací ve formuláři. Patnáctý až dvacátý řádek se postará o výpis případného nápovědného textu.
Tato šablona je univerzální, takže ji můžeme použít i v našem kontaktním formuláři. Je potřeba vytvořit další šablonu (templates/contact.html), která bude pomocí značky {% include %} využívat formulářovou šablonu:
{% extends "base.html" %}
{% block content %}
<h1>{% block title %}Kontakt{% endblock %}</h1>
{% if sent %}
<p>Vaše zpráva byla odeslána. Děkujeme!</p>
{% else %}
<form action="." method="POST">
<table>
{% include "form.html" %}
<tr>
<td></td>
<td><input type="submit" value="Odeslat"></td>
</tr>
</table>
</form>
{% endif %}
{% endblock %}
V této šabloně se podle hodnoty proměnné sent uživateli zobrazí potvrzující hláška nebo formulář. Hodnota se totiž v konstrukci if vyhodnotí jako True, pokud obsahuje nějaký neprázdný (nenulový) objekt. Může to být například neprázdný textový řetězec.
Kromě šablon potřebujeme i příslušný pohled, který formulář zpracuje a pokusí se poslat e-mail. Přidáme ho na konec souboru video_store/views.py:
from forms import ContactForm
from django.core.mail import mail_managers
def contact(request, sent):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
message = u'Uživatel vyplnil následující údaje:\n\n'
for item in form.fields.keyOrder:
if len(unicode(form.cleaned_data[item])) > 0:
message += form[item].label + u': ' + unicode(form.cleaned_data[item]) + u'\n'
mail_managers('Nová zpráva z kontaktního formuláře', message)
return HttpResponseRedirect('/kontakt/odeslano/')
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form, 'sent': sent}, context_instance=RequestContext(request))
Druhým argumentem pohledu je proměnná sent. Ta se pouze předá šabloně formuláře a podle jejího obsahu se určí, co se má zobrazit. Formulář je zasílán metodou POST, takže se dá lehce poznat, zda už byl vyplněn. To rozhodujeme podle objektu request (řádek 5). Pokud nebyl vyplněn, vypíšeme pouze prázdný formulář (řádek 19). V opačném případě vložíme do formuláře zadaná data (řádek 6) a zjistíme, jestli je vstup validní (řádek 8). Kupříkladu jestli e-mail vyhovuje určitému regulárnímu výrazu nebo jestli jsou vyplněny všechny povinné položky. Pokud je všechno v pořádku, sestavíme text e-mailu a rozešleme jej lidem, kteří jsou zodpovědní za správu stránky. Po úspěšném odeslání e-mailu dotaz přesměrujeme na stránku s hláškou, abychom předešli případům, kdy se při náhodném obnovení stránky formulář zpracovává znovu.
u), jinak může dojít při zadání diakritického textu k vyhození výjimky UnicodeError (selhání při dekódování znakové sady).Ještě než nastavíme URL, měli bychom určit e-mailové adresy, na které se bude obsah kontaktního formuláře rozesílat. Stačí upravit konstantu MANAGERS v souboru settings.py například takto:
MANAGERS = (
('Jan Novák', 'honza@example.cz'),
('Franta Uživatel', 'franta@example.cz'),
)
Pokud se e-mailový server nenachází na počítači, na kterém aplikaci provozujeme, musíme ve stejném souboru přenastavit konstanty začínající prefixem EMAIL, jinak nám rozesílání e-mailů nebude fungovat. Bez e-mailového serveru lze skript také testovat, jenom je potřeba funkci mail_managers volat s parametrem fail_silently=True, aby se potlačila chybová hláška.
A konečně, teď jenom stačí přidat správný řádek do proměnné urlpatterns v souboru urls.py (z důvodů přehlednosti opět zkráceno):
urlpatterns = patterns('hrajeme_si',
# ...
(r'^kontakt(|/odeslano)/$', 'video_store.views.contact'),
)
Regulární výraz (|/odeslano) přiřadí proměnné sent buď prázdnou hodnotu nebo řetězec '/odeslano', který stačí k vyvolání hlášky o odeslání.
Související odkazy
- Formuláře na Djangoproject.com
- Sedmá kapitola v The Definitive Guide to Django
- Ukázkový příklad ke stažení.
Příště se dozvíme něco o autentizaci a autorizaci uživatelů v Djangu.
Školení Google+ pro firmy

- Jak využít Google+ pro firemní komunikaci a marketing.
- Čím se liší Google+ od Twitteru a Facebooku z pohledu firemního využití.
- Jak využít Google+ v souladu s pravidly užívání.
- Založení Google+ Page (Stránky) krok po kroku, včetně praktických tipů.
Detailní informace o školení Google+ »
Seriál Hrajeme si s Djangem
- Django: Prezentace dat
- Django: Prezentace dat podruhé
- Django: Zpracovávání formulářů
- Django: Autentizace a autorizace
- Django: Nahrávání souborů
Přehled názorů
Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.



