První aplikace v Djangu, část 2

Tento návod začíná tam, kde skončila první část ukázkové aplikace. Budeme pokračovat v naší webové anketní aplikaci a zaměříme se na automaticky generované administrativní rozhraní Djanga.

Filozofie

Vytváření administračních stránek pro běžnou správu obsahu je únavná a nudná práce, která nevyžaduje příliš mnoho kreativity. Django přichází s možností automatického vytvoření administračního rozhraní pro definované modely.

Django bylo napsáno v novinářském prostředí, kde byl jasně vymezen rozdíl mezi těmi kdo tvoří obsah, a těmi kdo jej konzumují. Správci stránek používají administrační systém pro přidávání zpráv, událostí, sportovních výsledků atd., a tento obsah je zveřejňován. Django řeší problém vytváření jednotného rozhraní pro všechny tvůrce obsahu.

S administračním rozhraním se běžný návštěvník stránek nemusí vůbec potkat – je pouze pro ty, kteří web spravují.

Aktivace administračního rozhraní

Administrační rozhraní Djanga není ve výchozí konfiguraci zapnuto – musíte je sami aktivovat. Stačí provést tyto tři úkony:

  • Přidejte “django.contrib.admin” do seznamu v INSTALLED_APPS.

  • Spusťte python manage.py syncdb. Protože jste přidali do INSTALLED_APPS novou aplikaci, je třeba vytvořit všechny nové databázové tabulky.

  • Upravte soubor mysite/urls.py a odkomentujte tři řádky, které se odkazují na administraci (admin). Soubor urls.py obsahuje výrazy, které mapují URL adresy na konkrétní aplikace. V další části návodu se na URLconf podívame podrobněji, pro tentokrát více vědět nepotřebujete. Výsledek vašich úprav by měl vypadat asi takto:

    Změna ve vývojové verzi: Metoda která do pravidel přidává administrátorské URL adresy se v Djangu od verze 1.1 změní.

    from django.conf.urls.defaults import *
    
    # Uncomment the next two lines to enable the admin:
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = patterns('',
        # Example:
        # (r'^mysite/', include('mysite.foo.urls')),
    
        # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
        # to INSTALLED_APPS to enable admin documentation:
        # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
    
        # Uncomment the next line to enable the admin:
        (r'^admin/', include(admin.site.urls)),
    )
    

    (Tučně zvýrazněné řádky nesmí být zakomentovány.)

Spouštíme vývojový server

Spusťte vývojový server a pojďme se podívat, jak admnistrační rozhraní vypadá.

Vzpomeňte si na první díl tohoto průvodce. Vývojový server se spouští příkazem:

python manage.py runserver

Nastartujte prohlížeč a přejděte na “/admin/” na vašem localhostu — např., http://127.0.0.1:8000/admin/. Měli by jste vidět přihlašovací stránku:

Přihlašovací obrazovka administračního rozhraní

Uvnitř administrace

Teď se zkuste přihlásit. (V první části našeho návodu jsme vytvářeli účet pro superuživatele, vzpomínáte si? Pokud jste si jej nevytvořili, nebo jste zapomněli heslo, můžete si vytvořit nový.) Měli by jste vidět hlavní stránku administrace:

Hlavní stránka administračního rozhraní

Uvidíte řádky se skupinami, uživateli a weby, tj. základními aplikacemi, které přichází společně s Djangem.

Administrace anketní aplikace

Ale kdepak je naše anketní aplikace? Na hlavní stránce není zobrazena…

Stačí udělat jediné: říct Django administraci, že má spravovat i objekty Poll. Vytvořte soubor s názvem admin.py ve vašem adresáři polls a upravte ho, aby vypadal asi takhle:

from mysite.polls.models import Poll
from django.contrib import admin

admin.site.register(Poll)

Restartujte vývojový server, aby se změny projevily. Obyčejně server změněný kód načte automaticky, ale vytvoření nového souboru tuto akci nevyvolá.

Prohlídka administrace

Teď, když jsme Poll zaregistrovali, Django aplikaci zobrazí na hlavní stránce administrace:

Hlavní admin stránka už zobrazuje i naši anketu

Klikněte na “Polls.” Zobrazí se vám seznam anket z databáze. Momentálně máme v databázi pouze anketu “What’s up?”, kterou jsme vytvořili během první části průvodce:

Seznam anket, momentálně s jedinou položkou

Pokusíme se anketu změnit. Klikněte na řádek “What’s up?”:

Změnový formulář pro objekt ankety

Zde si všimněte:

  • Formulář je automaticky vygenerován podle modelu.
  • Jednotlivé typy modelových polí (DateTimeField, CharField) jsou přiřazeny ke správnému HTML widgetu. Každé pole ví, jak se má v administraci zobrazit.
  • U každého pole typu DateTimeField se zobrazí JavaScriptoví pomocníci: vedle políčka s datumem se objeví odkaz “Today” a kalendář, vedle času odkaz “Now” se seznamem nejčastěji zadávaných časů.

Ve spodní části stránky je zobrazeno několik tlačítek:

  • Save (Uložit) — Uloží změny a vrátí se na stránku s přehledem pro tento typ objektu.
  • Save and continue editing (Uložit a pokračovat v úpravách) — Uloží změny a znovu načte administrační stránku pro úpravy tohoto objektu.
  • Save and add another (Uložit a přidat další) — Uloží změny a načte nový, prázdný formulář pro tento typ objektu.
  • Delete (Smazat) — Zobrazí potvrzovací stránku pro smazání.

Změňte hodnotu pole “Date published” kliknutím na odkazy “Today” a “Now”. Pak objekt s pomocí “Save and continue editing” uložte. Klikněte na “History” vpravo nahoře. Uvidíte stránku se seznamem všech změn provedených na tomto objektu prostřednictvím administračního rozhraní, včetně informace o čase a uživateli:

Stránka historie pro objekt ankety

Úprava vzhledu administračních formulářů

Není to báječné? Prostým zavoláním admin.site.register(Poll) Django dokázalo zprovoznit změnový formulář pro editaci objektu. Dokážete si představit tu hromadu kódu, kterou jste nemuseli psát? Vzhled formuláře Django odvodilo z definice modelu. Je ale docela možné, že vám jeho podoba nevyhovuje. Naštěstí máme po ruce mechanismy, kterými můžeme zobrazení administračních formulářu ovlivňovat.

Ukažme si to na konkrétním případě — v editačním formuláři prohodíme pořadí políček. Během registrace objektu nahradíme volání admin.site.register(Poll) za tyto řádky:

class PollAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question']

admin.site.register(Poll, PollAdmin)

Postup je jednoduchý — vytvoříme administrátorský objekt a předáme jej jako druhý parametr při volání admin.site.register().

Uvedená změna se projeví prohozením pořadí polí “Date published” a “Question”:

Pole byla přehozena

Teď to možná působí směšně (prohazovat dvě políčka), ale u modelů s desítkami položek je změna pořadí důležitým detailem z hlediska použitelnosti vaší aplikace.

A když už mluvíme o formulářích s tucty polí, možná budete chtít rozdělit formulář na několik skupin:

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Poll, PollAdmin)

První prvek každé n-tice ve fieldsets je titulek skupiny. Takhle bude váš formulář po změně vypadat:

Formulář má nyní skupiny polí

Ke každému poli můžete přiřadit libovolnou HTML třídu (class). Django nabízí třídu “collapse”, která určenou skupinu polí zobrazí sbalenou. To se hodí v případech, kdy máte dlouhý formulář s větším počtem polí, které se často nepoužívají:

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
Skupina polí je sbalená

Přidávání souvisejících objektů

Tak, administrační rozhraní pro Anketu (Poll) máme hotové. Ale každá Anketa je složena z několika Voleb (Choices) a ty se nám v administračním rozhraní ještě nezobrazují.

Zatím.

Tento problém lze vyřešit dvěma způsoby. Buď Volby zaregistrujeme podobně, jako jsme to udělali u Ankety. Řešení je jednoduché:

from mysite.polls.models import Choice

admin.site.register(Choice)

Teď budou “Volby” další položkou v administračním rozhraní. Formulář “Add choice” bude vypadat asi takhle:

Administrační stránka pro možnosti (Choices)

V tomto formuláři je pole “Poll” zobrazeno jako “selektítko”. Django ví, že ForeignKey má být v administraci zobrazen jako <select> box. Po rozbalení zjistíte, že máme zatím definovanou pouze jednu anketu.

Také si všimněte zeleného symbolu plus (“Add Another”, česky “Přidat další”) vedle políčka “Poll”. Každý objekt, který se prostřednictvím vztahu ForeignKey odkazuje na jiný, dostane v administračním rozhraní tuto volbu automaticky. Když na symbol kliknete, vyskočí vám okno s formulářem “Add poll”. Pokud v tomto okně přidáte anketu a znovu kliknete na “Save,” Django uloží anketu do databáze a dynamicky ji nastaví jako vybranou možnost ve formuláři “Add choice”, na který se právě dívate.

Přidávání voleb “Choices” jde ale zrealizovat i efektivněji, už ve chvíli vytváření ankety.

Odstraňte volání register() pro model “Choices”. Upravte registrační kód pro Poll, aby vypadal takto:

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Poll, PollAdmin)

Tento kód Djangu říká: “Volby (Choices) budou spravovány v administraci pro Ankety (Poll). Pro správu voleb zobraz 3 pole.”

Načtěte si stránku “Add poll” a podívejte se, jak teď vypadá:

Stránka pro přidání ankety teď obsahuje i volby (Choices)

Funguje to následovně: Na stránce s anketou budou vždy zobrazeny 3 bloky pro zadání voleb (což je specifikováno pomocí extra). Pokaždé, když si zobrazíte stránku s editací existujícího objektu, budou na vás čekat tři nová pole pro zadání dalších voleb (i přesto, že anketa už nějaké volby definovány má).

Má to ale malý háček. Zobrazení všech polí zabere na stránce hodně místa. Pro související objekty Django naštěstí nabízí i tabulkové zobrazení; stačí změnit deklaraci ChoiceInline aby vypadala takhle:

class ChoiceInline(admin.TabularInline):
    #...

S použitím TabularInline (namísto StackedInline), budou související objekty zobrazeny v kompaktnějším tabulkovém formátu:

Stránka pro přidávání ankety je teď kompaktnější

Upravte si výpis objektů

Teď, když už administrační stránka pro ankety vypadá dobře, pojďme vyladit výpis “change list” — ten zobrazuje všechny ankety v systému.

Jeho současná podoba je následující:

Výpis 'Change list' pro ankety

Ve výchozím nastavení Django zobrazuje str() každého objektu. Někdy by se ale hodilo, kdybychom viděli jednotlivá pole modelu. Pro tento účel použijte možnost list_display se seznamem polí, které chcete ve sloupcích zobrazit:

class PollAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question', 'pub_date')

A ještě jedna fajnovost — přidejme uživatelskou metodu was_published_today z první části tohoto průvodce:

class PollAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question', 'pub_date', 'was_published_today')

Po všech těchto úpravách bude výpis change list pro ankety vypadat takto:

Aktualizovaný Change list pro ankety

Kliknutím na záhlaví sloupce seřadíte objekty podle hodnot ve sloupci — kromě záhlaví was_published_today, protože řazení podle výstupu libovolné metody není podporováno. Také si všimněte, že záhlaví sloupce was_published_today má ve výchozím nastavení stejný název jako je jméno metody (podtržítka jsou nahrazena mezerami). Tohle můžete změnit přidáním atributu short_description (v souboru models.py):

def was_published_today(self):
    return self.pub_date.date() == datetime.date.today()
was_published_today.short_description = 'Published today?'

Přidejme do change listu další vylepšení: filtry. Dopište následující řádek do třídy PollAdmin:

list_filter = ['pub_date']

Tato volba přidá postraní lištu “Filter”, která umožňuje filtrovat výpis Change list podle hodnot pole pub_date:

Výpis Change list pro ankety, tentokrát včetně filtru

Typ zobrazeného filtru závisí na poli, podle kterého se má filtrovat. Protože pub_date je DateTimeField, Django ví, že má zobrazit volby pro pole DateTimeField: “Any date” (Jakékoliv datum), “Today” (Dnes), “Past 7 days” (Posledních 7 dní), “This month” (Tento měsíc) a “This year” (Tento rok).

Už se nám ten admin začíná pěkně rýsovat, že? A to stále není vše — přidejme nyní možnost vyhledávání:

search_fields = ['question']

Uvedená formule přidá vyhledávací políčko na začátek stránky. Když uživatel zadá nějakou hodnotu, Django prohledá pole question. Můžete použít tolik polí, kolik chcete — i když, protože se pro vyhledávání používá dotaz LIKE, zkuste to nepřehánět, aby to vaše databáze vydržela.

A jsme u posledního vylepšení: protože objekty anket obsahují pole s datumem, bude pěkné, když budeme moci ankety procházet podle data (např. “zobraz všechny ankety publikované v listopadu 2008”). Dopište tento řádek:

date_hierarchy = 'pub_date'

Tímto způsobem se na začátek stránky přidá hierarchická navigace podle data. Nejvyšší úroveň zobrazuje všechny dostupné roky, v nižších pak měsíce a jejich dny.

Na konec je dobré poznamenat, že můžete ovlivnit i stránkování výpisu. Výchozí nastavení zobrazuje 50 objektů na jedné stránce.

Upravte si kompletní vzhled prostředí

Je jasné, že zobrazení nadpisu “Django administration” na každé stránce administračního rozhraní je hrozné. Tento text přímo volá po změně.

Náprava se dá provést poměrně jednoduše — změnou konkrétní šablony.

Otevřete váš soubor s nastavením (mysite/settings.py, vzpomínáte?) a podívejte se na proměnnou TEMPLATE_DIRS. TEMPLATE_DIRS je seznam adresářů, které se při načítání šablonového systému postupně prochází. Je to vyhledávací cesta.

Ve výchozím nastavení je TEMPLATE_DIRS prázdné. Přidejme tam řádek, aby Django vědělo, kde hledat naše šablony:

TEMPLATE_DIRS = (
    "/home/my_username/mytemplates", # Nastavte na svuj adresar.
)

Zkopírujte šablonu admin/base_site.html ze zdrojových kódů Djanga (django/contrib/admin/templates) do podadresáře admin složky, kterou jste nastavili ve volbě TEMPLATE_DIRS. Například, pokud TEMPLATE_DIRS obsahuje “/home/my_username/mytemplates”, jak je uvedeno výše, zkopírujte django/contrib/admin/templates/admin/base_site.html do /home/my_username/mytemplates/admin/base_site.html. Nezapomeňte na ten podadresář admin!

Pak už jenom upravte soubor a nahraďte standardní text něčím, co se vám tam hodí.

Šablona obsahuje spoustu na první pohled možná nepřehledných výrazů. Třeba {% block branding %}` nebo {{ title }}. Výrazy “{% a {{ jsou součástí šablonového systému, které Django v tu pravou chvíli přetaví do finálního HTML kódu. Podrobnosti probereme v třetí části návodu.

Jakákoli výchozí šablona administračního rozhraní může být nahrazena. Budete postupovat stejně, jako tomu bylo u souboru base_site.html — zkopírujte šablonu z výchozího adresáře do vašeho vlastního adresáře a tam ji upravte dle libosti.

Mazaní čtenáři se zeptají: Ale pokud nastavení TEMPLATE_DIRS bylo na začátku prázdné, jak Django našlo šablony? Odpověd je, že Django si standardně ověří existenci podadresáře templates/ v adresáři každé aplikace, pro případ, kdyby uživatel žádné cesty k šablonám nedefinoval. Další podrobnosti naleznete v dokumentaci pro template loader.

Upravte si hlavní stránku administrace

Když už jsme u toho, asi si budete chtít změnit také vzhled hlavní stránky administrace.

Ve výchozím nastavení zobrazuje v abecedním pořadí všechny aplikace z proměnné INSTALLED_APPS, které byly zaregistrovany do administračního rozhraní. Možná budete chtít udělat v rozložení stránky významné změny. Hlavní stránka je přeci jen jednou z nejdůležitějších a měla by se dát jednoduše používat.

Šablona této stránky je schovaná v admin/index.html. (Dělejte to samé jako s admin/base_site.html v předchozí části — zkopírujte ji z výchozího adresáře do uživatelského adresáře). Prozkoumáním této šablony zjistíte, že používá šablonovou proměnnou app_list. Tato proměnná obsahuje každou nainstalovanou Django aplikaci. Místo této proměnné můžete ve své šabloně vytvořit “tvrdé” odkazy na administrační stránky pro jednotlivé objekty — prostě tak, jak vám to bude vyhovovat. Pokud nerozumíte, nezoufejte. Jak už bylo zmíněno, podrobnosti probereme v třetí části návodu.

Až budete se svým administračním rozhraním spokojeni, přečtěte si třetí část tohoto návodu a začněte pracovat na veřejných views (pohledech) pro ankety.