Scukařina, žádná dřina - díl druhý: Django je naše máma
V druhém díle Scukopříběhu se zaměříme na praktické momenty vývoje v Djangu. Představíme si sehranou trojici z vývojové laboratoře, zajedeme s databází k moři a nakonec lusknutím prstu připravíme vašemu klientovi velké administrační překvapení. Vše v článku, stačí jen kliknout a číst.
Seriál Scukařina, žádná dřina
- Scukařina, žádná dřina - díl první: agilně!
- Scukařina, žádná dřina - díl druhý: Django je naše máma
- Scukařina, žádná dřina - díl třetí: Djangová je náš táta
- Scukařina, žádná dřina - díl čtvrtý: jiná práce s CSS
- Scukařina, žádná dřina - appendix
Poznámka: Jde do tuhého. Obecnost jsme nechali v prvním díle, odteď musíte vědět, co to Django je, nebo alespoň zahrát melodii ve stupnici 1 2 b3 #4 5 b6 7. Stejně jako minule doporučuji seriál na Zdrojáku, přeložený tutoriál nebo oficiální anglickou dokumentaci.
Zdlouhavé konfigurace? Nikoliv
Django obsahuje tři naprosto zásadní pomůcky: vývojový server, podporu SQLite a interaktivní shell.
Vývojový server vás odstiňuje od nutnosti konfigurovat lokální webový server (třeba Apache). Jednoduše vlezete do adresáře s projektem, napíšete ./manage.py runserver a do prohlížeče vložíte adresu http://127.0.0.1:8000/
SQLite je jednou z Djangem podporovaných databází. Milé na tomto capartovi je to, že se nemusí skoro nic nastavovat. Stačí do souboru settings.py uvést dvě konstanty (DATABASES ENGINE a NAME ) a databáze jede.
Pokud používáte Python, určitě jste si už potykali s jeho shellem. Django disponuje podobnou konzolí, která oproti staršímu bráchovi získává možnost manipulovat s objekty Djanga a vašeho projektu (např. provádět ORM dotazy).
Všechny zmíněné celky jdou ruku v ruce s rychlým a efektivním vývojem:
- Před napsáním kódu nejdříve podráždím aplikaci přes konzoli
./manage.py shell, a hledám optimální formu algoritmu. - Při raném návrhu modelů zase často měním databázová pole. Protože v této fázi zpravidla nemám v DB žádná důležitá data, smažu soubor s SQLite databází a zavolám
./manage.py syncdb(přece se nebudu zdržovat SQLALTERy). - A vývojový server? Ten doceníte při ladění chyb. Stačí do kódu vložit pár
printů nebo rovnouimport pdb; pdb.set_trace()a hned v konzoli uvidíte, co se děje (indián to sice umí taky, ale složitěji).
Poznámka: Pokud budete do svého projektu později nasazovat „dospělejší“ databázi a chcete zůstat nervově stabilní, moc to s SQLite nepřehánějte. Mezi jednotlivými DB totiž existují drobné rozdíly, které by se mohly po nasazení na produkčním serveru nepříjemně projevit.
Cesta na jih
Migrace — Achillova pata Djanga. Na rozdíl od Railsů Django neobsahuje nativní podporu pro databázové migrace. Pokud tedy v průběhu vývoje změníte existující model, musíte si jej sami na databázové úrovni upravit. Naštěstí zde ale máme aplikaci South, která nám s touto bolístkou pomůže.
Vytvoření migrace
Předpokládejme, že už nějakou dobu vyvíjíte aplikaci customers.Customer, v databázi máte uložena důležitá data a přijde požadavek na změnu modelu. Vlezte do systémové konzole a zavolejte:
./manage.py convert_to_south customers
Tímto způsobem dáte „Jižanovi“ najevo, že má vaši aplikaci customers sledovat a zapamatovat si její aktuální stav. Současně vznikne uvnitř customers podadresář migrations, do kterého si bude South ukládat migrační skripty.
Zpět k aplikaci — proveďte plánovanou úpravu modelu a opět z konzole zavolejte:
./manage.py schemamigration customers --auto
customers je jméno migrované aplikace a parametr --auto způsobí, že South provede automatickou detekci změn a vygeneruje kód migrace. Schválně se teď podívejte do adresáře customers/migrations/, kde objevíte nový soubor a uvnitř v metodě forward kód provádějící změnu.
Aplikování migrace
Všechny dosud provedené operace ale s modelem, resp. tabulkou v databázi, reálně nic neprovedly. Aplikování migrací musíte spustit explicitně:
./manage.py migrate
Teprve teď budou databázové tabulky „lícovat“ s vašimi Django modely.
Migrace dat
Pokud svým modelem měníte databázové schéma (např. nahrazujete pole name za fname a lname) a zároveň dochází ke změně uložených dat (hodnotu uvnitř name rozbijete podle mezery, a uložíte do fname a lname), musíte si si tento úkol rozdělit do několika samostatných migrací. Například v první přidáte do modelu pole fname a lname, v druhé překonvertujete data a ve třetí smažete pole name. Mixovat migrace schémat a dat není dobrý nápad.
Vytvořit migraci pro pozměněný model už umíme. Co ale s tou konverzí? Toto:
./manage.py datamigration customers split_name
Parametrem datamigration vytvoříte migrační skript, který zdánlivě nic nedělá (metoda forward je prázdná). V tomto případě musíte sami doplnit kód, který se o konverzi dat postará:
def forwards(self, orm):
for c in orm.Customer.objects.all():
c.fname, c.lname = c.name.split(' ')
c.save()
Všimli jste si toho „orm“? Pokud na úrovni migrací přistupujete k modelům, nedělejte to obvyklou formou přes importy (např. from
myproject.customers.models import Customer), ale přes argument orm. Jde o to, že s pomocí „orm“ vytáhnete požadovaný (pseudo)model v takovém stavu, v jakém byl v době psaní skriptu.
Navážeme na dříve zmiňovaný příklad. V modelu Customer máme pole name, které chceme rozdělit do dvou samostatných polí. Veškerá již uložená data v DB chcete uchovat a zkonvertovat do nové podoby. Zapomenete ale na „orm pravidlo“ (importujete model Customer přímo). Na vašem počítači vše funguje jak má, ./manage.py migrate proběhne bez obtíží.
Po dokončení všech úprav se vrhnete na server: zaktualizujete zdrojové kódy, spustíte migrační skripty nad starou databází a… vyskakuje traceback s jakousi chybou. Haló, haló, co se stalo?
Vývoj na vašem počítači je kontinuální. Každou změnu v modelu promítáte do migrací a ty hned aplikujete na databázi. Modely a tabulky jsou vždy synchronní. Na serveru ale dojde ke skokové změně zdrojových kódů (např. spojením větve):
Datová migrace na serveru natáhne přes import nejaktuálnější podobu modelu, ta ale neodpovídá stavu databáze.
(kliknutím zobrazíte originální obrázek)
Využitím konstrukcí „orm.Model“ se podobným nepříjemnostem vyhneme.
Správcem za minutu
Pokud se to k vám ještě nedoneslo, tak administrační rozhraní Djanga je koží! O co jde?
Během desítek vteřin budete schopni rozjet komfortní webovou administraci pro kterýkoliv z modelů svého projektu. Schválně se podívejte do oficiální dokumentace django.contrib.admin — pouze svůj model zaregistrujete a pak s pomocí atributů třídy ModelAdmin ladíte jeho konkrétní podobu (vyhledávání, filtry, rozvržení prvků formuláře, …). Mňam!
Je přirozené, že časem z „atributové“ košilky vyrostete a budete chtít víc. Třeba:
- zobrazovat vypočítané hodnoty (tj. nejen to, co máte ve sloupcích DB tabulek)
- manipulovat pouze s objekty, na které má přihlášený uživatel právo
- vybavit editační formulář dalšími funkčními prvky…
- …nebo do něj dynamicky generovat data či rovnou formulářová pole
V tom případě se vám otevře další vesmír, protože django.contrib.admin vývojáři nabízí slušnou baterii „háčků“ (metod, které můžete přetížit vlastním kódem). Aplikace django.contrib.admin je právem označována za kyľafičr frameworku Django.
Praktická ochutnávka
Z počátku jsme na Scuku pro editaci podniku používali následující formulář:
Administrace podniku poskládaná z obvyklých atributů aplikace django.contrib.admin
Po vpuštění betatesterů nám ale začaly prudce přibývat recenze a hlášení o chybách. Pohodlnost správy se pomaličku vytrácela, protože jsme se museli neustále proklikávat jednotlivými obrazovkami administrace. Jeden večer jsem se proto spustil a zaflirtoval s Djangem:
Upravený administrační formulář nyní obsahuje informace i o provázaných modelech
Administrátor po rozkliknutí záznamu hned vidí seznam recenzí, hlášení o chybách a informaci o průměrném hodnocení podniku (která se počítá speciálním algoritmem).
Realizace
A cože se onu noc dělo? Asi vás zklamu, moc daleko jsme se nedostali. Stačilo totiž přetížit jednu metodu a vytvořit šablonu:
Soubor shops/admin.py:
from django.contrib import admin
class ShopAdmin(admin.ModelAdmin):
# ...
# (obvykla konfigurace admin tridy)
# ...
def change_view(self, request, object_id, extra_context=None):
# do kontextu sablony propasirujeme promennou "problems"
# se seznamem dosud nevyresenych hlaseni o chybach
shop = get_object_or_404(Shop, id=object_id)
extra_context = {
'problems': ShopProblem.objects.filter(shop=shop, resolved=False)
}
return super(ShopAdmin, self).change_view(request, object_id, extra_context)
Soubor templates/admin/shops/shop/change_form.html:
{% extends "admin/change_form.html" %}
{% load i18n %}
{# CSS trida, ktera zpusobi rozdeleni layoutu na 2 sloupce #}
{% block coltype %}colMS{% endblock %}
{% block content %}
{{ block.super }} {# puvodni obsah -- formik na leve strane #}
<div id="content-related">
<div class="module" id="recent-actions-module">
{% comment %}
HTML kod generujici obsah v pravem sloupci, napr.:
{% endcomment %}
<ul>
{% for obj in problems %}
<li>
<a href="/admin/shops/shopproblem/{{ obj.id }}/">
{{ obj.created|date }} od {{ obj.user }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endblock %}
No není to paráda?
Úskalí
Však to znáte, v každém vztahu to občas zajiskří a na povrch vyplavou skutečnosti, o kterých jste zatím neměli ani páru.
V případě Django administrace jsem kdysi narazil na neefektivitu v případě ukládání modelu, který měl na stránce hodně inline prvků. Po kliknutí na „Save“ se vygenerovalo 300+ SQL dotazů. Jindy mě zase zamrzelo, že celý django.contrib.admin je příliš pevně propojen s relačními databázemi a v případě použití NoSQL můžete na celý administrátorský komfort zapomenout.
Chce to ale víc času. Pokud se budete stýkat častěji a pochopíte limity toho druhého, budete schopni nepříjemným překvapením předcházet. Je to vztah jako každý jiný.
Co nás čeká příště?
Hrdinný Scuk.cz se pochlubí účinným preparátem na hubení bezobratlých, poodkryje nám jednu ze zavrhovaných praktik (pst!) a dokáže, že i bez orientačního smyslu najde na mapě, co potřebujete. Zůstaňte věrni, snad to dobře dopadne.
Š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 Scukařina, žádná dřina
- Scukařina, žádná dřina - díl první: agilně!
- Scukařina, žádná dřina - díl druhý: Django je naše máma
- Scukařina, žádná dřina - díl třetí: Djangová je náš táta
- Scukařina, žádná dřina - díl čtvrtý: jiná práce s CSS
- Scukařina, žádná dřina - appendix
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.