Dvojitá alchymie VI - traversal ještě více

25. 10. 2013 20:44 (aktualizováno) Petr Blahoš

Podívejte se na všechny díly seriálu nebo na zdrojáky příkladu.

Zase se podíváme na traversal. Zkusíme si do našeho schématu URL zamontovat pager a filtr. Všímám si, že se trošku vzdaluju původnímu tématu – formalchemy. Dnes se ho aspoň trochu dotkneme, právě v tom filtrování.

step10

Nejprve si vymyslíme schéma url. Minule jsme měli root, pod ním jméno modelu, a pak už ten konkrétní záznam, dosažený přes primární klíč: 

  • /
  • /ModelName/
  • /ModelName/id=324
Když tam chci zamontovat pager a filtr, tak logicky nějak omezuji model, takže si to upravím takto:
  • /
  • /ModelName-pagerdata-filterdata/
  • /ModelName-pagerdata-filterdata/id=324

Přičemž pagerdata i filterdata nechám nepovinná, a když nebudou, nemusí tam být ani ty pomlčky. Tak teď prosím:

# nezapomeňte git pull
cd step10
python setup.py develop

pserve --reload development.ini

Abychom mohli vyzkoušet pager, tak potřebujeme pár stránek dat. Když navštívíte http://localhost:6543/admin1, tak se Vám do tabulky person uloží 100 záznamů. Teď, pokud to někdo vůbec čte a zajímá ho to, tak mám cvičení: Upravte kód tak, aby z této akce přesměrovalo na výpis položek z tabulky person.

Pager

Pager je banální. pagerdata budou číslo stránky-počet položek na stránce. Parsování je v model/resources.py:Model­Context.__init__. Zajímavé je v get_grid, kde si sestavíme v SQLAlchemy dotaz, a pak voláme q[start:end], což zavolá vpodstatě select s limit a offset. Má to jeden problém. Pozná někdo jaký?

templates/list.mako pak zobrazuji ten pager, poměrně tupým způsobem. V reálné aplikaci bych to dělal trochu zapouzdřeněji. Také neznáme počet stránek, tím se zde nebudu zabývat (pokud si o to někdo v komentářích neřekne). Ještě se podívejte na způsob, jakým je řešeno další/předchozí. Pro kontext modelu máme views pojmenovaná prev a next, která samozřejmě dostanou ten kontext aktuální stránky. V těchto view prostě manipulujeme s číslem první stránky – vlastně upravíme aktuální kontext (který je platný jen v rámci právě zpracovávaného requestu), a pak na něj přesměrujeme.

Filtr

filterdata by měla být sekvence dvojic klíč=hodnota, urlencoded. Rozhodl jsem se nekomplikovat to, vlastní fitrování udělat tak, že zařadím výsledky, které v příslušném sloupci začínají danou hodnotou. model/resources.py:ModelCon­text.get_grid. Mnohem zajímavější je ale otázka, jak udělat ten formulář na filtr. Tady nás snad všechny napadne, že k tomu prostě musíme použít formalchemy, když už ho máme. Jenže formalchemy tam strčí i vztažené tabulky, a pokud je sloupec netextového typu (číslo, datum), tak tam dá speciální editovací pole. Já tady pracuju s hodně velkým zjednodušením – pro všechno používám textové pole (bez omezení délky nebo obsahu). V model/tools.py definuju QFieldSet, ve kterém zakážu relations, a o všech polích prohlásím, že je to text. Jako druhou věc, definuju vlastní renderer pro textové pole, který nikdy neomezuje délku, a který se nepokouší najít nějakou default hodnotu. Formulář pro vlastní filtr pak dostaneme z ModelContext.get_q_fs, kterému předhodíme naše filterdata. Vygeneruje nám formulář, který zpracujeme v views/views.py:list_filter, kde zase upravíme aktuální kontext, a přesměrujeme.

Proč?

Takováhle struktura aplikace má jednu výhodu. To filtrování a ten paging vydrží. Když vyvolám mazání, tak se z něj vrátím na původní výpis (samozřejmě bez toho smazaného záznamu). Stejně tak s editací. Kdybych měl extra akci k prohlížení detailů o položce (což bych ve skutečné aplikaci měl), tak by to taky fungovalo. Prostě, teď jsem na konkrétní stránce, k konrétním filtru, a tam taky zůstanu. Nepotřebuju k tomu session, nemanipuluju s query stringem. S generováním URL mi pomáhá framework.

Sdílet