Přejít k navigační liště

Zdroják » Různé » Scukařina, žádná dřina – díl druhý: Django je naše máma

Scukařina, žádná dřina – díl druhý: Django je naše máma

Články a Různé

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.

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 SQL  ALTER y).
  • A vývojový server? Ten doceníte při ladění chyb. Stačí do kódu vložit pár print ů nebo rovnou import 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.

Komentáře

Subscribe
Upozornit na
guest
14 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Voy

Trochu jsem čekal, že se dozvíme víc o tom jak se vyvíjel třeba datový model Scuku a k jakým změnám v designu v průběhu docházelo. Zajímavé by to bylo už jen proto, že do Scuku přispěvatelé ládovali obsah v podstatě už od ranných prototypů (chápu-li to správně). Teď to vypadá spíš jako stý první tutoriál o djangu, což mi přijde trochu škoda. Ale možná, že se dočkáme víc v dalších dílech… ?

EskiMag

Pripájam sa k tomuto názoru. Radšej ako technické detaily, ktoré sa dajú dočítať v tutoriáloch a knihách, by sme si radšej prečítali také tie viac filozofické a architektonické problémy, ktoré museli vývojári riešiť. Mimochodom ten obrázok s diagramom vývoja je veľmi malý a teda nečitateľný.

Martin Malý

Obrázek opraven, moje vina, omlouvám se.

architekt_

Mě se naopak líbí, že se autor zbytečně nepouští do konkrétních detailů pozadí Scuku. Místo toho oceňuji, že na jednoduchých příkladech z praxe ukazuje, jak se elegantně vypořádat s běžnými problémy, jako ta migrace dat při změně datových modelů. Myslím si, že každý vývojář si užil nějaké to neefektivní ALTERování databáze a minimálně pro mne bylo toto seznámení s aplikací South velmi přínosné.

Pitrsonek

Ahoj v Pythonu a Django jsem nikdy nedělal. Programuji v PHP přesněji CakePHP, ale chtěl bych se naučit Python a Django.
Jaké zdroj nebo nejlépe knihy bys doporučil pro studování Pythonu a Django.
Na co je důležité se zaměřit v Pythonu a jak postupovat.
Děkuji moc seriál to bude moc pěkný, už se těším na další díly.

Mintaka

Jedním z důvodů, pro které jsem si Django vybral byla propracovaná dokumentace. Enjoy: http://www.djangobook.com/

architekt_

Jako základ si stačí projít oficiální tutoriál Pythonu http://docs.python.org/release/2.6.5/tutorial/index.html Na serveru py.cz je i český překlad http://www.py.cz/TutorialyLiteratura Sice je pro starší verzi Pythonu 2.2, ale ty základní principy jsou stále stejné.
Neuškodí si také prolétnout Library Reference a Language Reference http://docs.python.org/release/2.6.5/index.html , aby člověk trochu nasál do podvědomí, co ten python všechno umí.
A pak už se stačí vrhnout rovnou na Django a jeho oficiální tutoriál. http://docs.djangoproject.com/en/1.2/intro/tutorial01/

Martin Malý

Loni vycházel na Zdrojáku seriál Hrajeme si s Djangem, ten může být taky dobrým odrazovým můstkem…

Pitrsonek

Paráda díky za tipy a odkazy, už jsem si trochu prolítl python a vypadá to v pohodě, v podstatě jako ostatní srkiptovací jazyky. Sice se mi moc nepozdáva syntax trošku nepřehledná snad se dají používat pro bloky {} na ty jsem zvyklý a přijde mi to o hodně přehlednější.

Martin Malý

Nerad bych vás nějak odradil, ale prozradím, že bloky se do složených závorek nedávají, vyznačení bloků odsazením je jedním z nejvýraznějších rysů Pythonu (a tedy i Djanga). Ale jde jen o zvyk, ostatně i v C-like jazycích by se mělo odsazovat stejně jako v tom Pythonu…

Pitrsonek

Bohužel, právě jsem na to narazil.
Také jsem našel dobrý Python tutoriál v CZ:
http://macek.sandbox.cz/texty/python-tutorial-cz/python-tutorial-cz-a4-2.2.pdf

Bruce

Veľa ľudí považuje nutné odsadzovanie blokov a absenciu {} v Pythone za niečo neprekonateľné, ale ja si myslím, že to je len silou mocou hľadanie zámienky, prečo nie Python. Na Python som prešiel z PHP, ale nad odsadzovaním som sa nikdy ani nepozastavil a nikdy som to nepovažoval za problém. Oproti PHP je zápis kódu kratší a niektoré veci sa zapisujú oveľa jednoduchšie.
Django môžem len doporučiť, na pár riadkov máte veľa funkcionality a vývoj ide pomaly tak nejako sám :)

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.