Bottle/Tutoriál

Tutoriál k pythonímu frameworku Bottle. Necháme se zpočátku inspirovat tutoriálem http://bottlepy.org/docs/dev/tutorial.html

Začněme experimentovat s jednosouborovou instalací:

01-nazdarek editovat

#!/usr/bin/python3 

from bottle import route, run

@route('/nazdar')
def hello():
    return "Nazdárek náš milý světe!"

run(host='localhost', port=8080, debug=True)

To co je v závorce za @route je cesta v URL, kam se má daná stránka umístit.

Dobře si povšimneme, že do webové stránky nepíšeme příkazem print, ale to, co chceme zobrazit, musíme dát do příkazu return.

Soubor uložíme do stejného adresáře pod jménem 01-nazdarek.py, přidělíme příslušná práva a spustíme:

chmod u+x 01-nazdarek.py
./01-nazdarek.py
Bottle v0.13-dev server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

Podíváme se na http://localhost:8080/nazdar a vidíme:

 Nazdárek náš milý světe!


02-semtam editovat

Webová sajtna má zpravidla více stránek. Demonstrujeme si web, který má dvě stránky, umístěné na URL:

#!/usr/bin/env python3

from bottle import route, run

@route('/')
def root():
    return "Tak jsme tady. Jdi <a href=\"tam\">tam!</a>"

@route('/tam')
def tam():
    return "Tak tam jsme a jdeme zase <a href=\"/\">zpátky</a>..."

run(host='localhost', port=8080, debug=True)

Všimneme si, že jak se proklikáváme tam a zase zpátky, server nám za příkazovou řádkou, ze které jsme skript pustili, hlásí:

127.0.0.1 - - [02/Oct/2015 04:46:50] "GET / HTTP/1.1" 200 41
127.0.0.1 - - [02/Oct/2015 04:46:51] "GET /tam HTTP/1.1" 200 41
127.0.0.1 - - [02/Oct/2015 04:46:54] "GET / HTTP/1.1" 200 41
127.0.0.1 - - [02/Oct/2015 04:47:59] "GET /tam HTTP/1.1" 200 41

03-dyn_cesty.py editovat

Jako dynamické cesty se označují cesty v URL, které nemusí být předem dané, ale program jména v cestě vyhodnotí a podle toho vytvoří stránku:

#!/usr/bin/env python3

from bottle import route, run

@route('/')
def root():
    return """
<ol>
  <li><a href="jedna">jedna</a></li>
  <li><a href="dva">dva</a></li>
  <li><a href="tři">tři</a></li>
<ol>
"""

@route('/<jmenostranky>')
def stranka(jmenostranky):
    return "Tak jsme na stránce <i>", jmenostranky, "</i> a jdeme zase <a href=\"/\">zpátky</a>..."

run(host='localhost', port=8080, debug=True)

04-error.py editovat

Ošetření chyb:

#!/usr/bin/env python3

from bottle import error, run

@error(404)
def error404(err):
    return 'Chybka č. 404 se vloudila!<br>Čiliže stránka tady žádná není :-('
    
run(host='localhost', port=8080, debug=True)

05-templ editovat

Šablony (templates) umožňují stránky v HTML kódu, zahrnujícím základní elementy jazyka Python (například větvení):

#!/usr/bin/python3

from bottle import route, run, template

@route('/nazdar')
@route('/nazdar/<name>')
def hello(name='NIKDO'):
    return template('nazdar1', name=name)

run(host='localhost', port=8080, debug=True)

Do podadresáře ./view (tento defaultní název podadresáře pro šablony můžeme změnit nastavením seznamu bottle.TEMPLATE_PATH) umístíme soubor šablony nazdar1.tpl

    <h2>Nazdar!</h2>
%if name == 'NIKDO':
    <p>Nevím, jak se jmenuješ.</p>
    <p>Ty nikdo nejsi?</p>
%else:
    <p>Ty jsi {{name.title()}}?</p>
    <p>Jak se máš?</p>
%end

Potom z adresy http://localhost:8080/nazdar dostaneme odpověď:

zatímco z adresy např. http://localhost:8080/nazdar/čenda dostaneme:

06-view editovat

Stejného výsledku jako výše můžeme (namísto volání funkce template) dosáhnout pomocí @view:

#!/usr/bin/env python3

from bottle import route, view, run

@route('/nazdar')
@route('/nazdar/<name>')
@view('nazdar1')
def hello(name='NIKDO'):
    return dict(name=name)

run(host='localhost', port=8080, debug=True)

07-SimpleTemplate editovat

Šablony jsou renderovány strojem, zvaným SimpleTemplate podle několika základních pravidel:

Inline editovat

{{...}} Do dvojitých složených závorek můžeme vložit jakýkoliv pythoní kód, jehož výstupem je řetězec znaků, který bude vložen na stránku (např. proměnná, výraz atd.)

Speciální znaky HTML kódu jsou přitom automaticky escapovány; pokuď si toho nepřejeme, vložíme před začátek kódu vykřičník: {{!...}}

Embeded editovat

Vložený jednořádkový kód uvozujeme znakem %, víceřádkový kód uzavřeme do <% ... %>

Kód je psaný podle všech pravidel Pythonu se dvěma výjimkami:

  1. Indentace (zarovnání) je ignorována
  2. Konce bloků, které by normálně byly vyznačeny zarovnáním, musí být explicitně vyznačeny klíčovým slovem % end

Funkce editovat

Každá šablona může využívat zvláštní funkce:

  • include(sub_template, **variables) – umožní vložit další šablonu
  • rebase(name, **variables) – tuto šablonu označí tak, aby mohla být později vložena do jiné šablony
  • defined(name) – vrátí logické ANO, pokud šablona s takovým názvem existuje
  • get(name, default=None) – vrátí proměnnou anebo defaultní hodnotu
  • setdefault(name, default) – pokud taková proměnná není definovaná, nastaví její defaultní hodnotu

Podrobnější popis SimpleTemplate je na http://bottlepy.org/docs/dev/stpl.html

Jako příklad si napíšeme prográmek, který nám zobrazí násobilku:

#!/usr/bin/env python3

from bottle import route, view, run

@route('/mul')
def mul():
    return "<h2>Násobilka<h2>Vlož číslo za lomítko do URL"

@route('/mul/<number>')
@view('multiply')
def mul(number):
    return dict(numb=number)

run(host='localhost', port=8080, debug=True)

Šablona multiply.tpl:

<h1>Násobilka {{numb}}</h1>

<table>
<%
  n = int(numb)
  for q in range(1, 10+1):
%>
      {{!'<tr align="right"> <td>{:2}</td> <td> × </td> <td>{:2}</td> <td> = </td> <td>{:3}</td> </tr>'.format(q, n, q*n)}}
% end
</table>

Pro zobrazení např. násobilky 3 jdeme na odkaz http://localhost:8080/mul/3

Formátování v Pythonu zde pro zobrazení webové stránky sice nemá žádný význam, ale výrazně nám zpřehlední vygenerovaný HTML kód:

<h1>Násobilka 3</h1>

<table>
	<tr align="right"> <td> 1</td> <td> × </td> <td> 3</td> <td> = </td> <td>  3</td> </tr>
	<tr align="right"> <td> 2</td> <td> × </td> <td> 3</td> <td> = </td> <td>  6</td> </tr>
	<tr align="right"> <td> 3</td> <td> × </td> <td> 3</td> <td> = </td> <td>  9</td> </tr>
	<tr align="right"> <td> 4</td> <td> × </td> <td> 3</td> <td> = </td> <td> 12</td> </tr>
	<tr align="right"> <td> 5</td> <td> × </td> <td> 3</td> <td> = </td> <td> 15</td> </tr>
	<tr align="right"> <td> 6</td> <td> × </td> <td> 3</td> <td> = </td> <td> 18</td> </tr>
	<tr align="right"> <td> 7</td> <td> × </td> <td> 3</td> <td> = </td> <td> 21</td> </tr>
	<tr align="right"> <td> 8</td> <td> × </td> <td> 3</td> <td> = </td> <td> 24</td> </tr>
	<tr align="right"> <td> 9</td> <td> × </td> <td> 3</td> <td> = </td> <td> 27</td> </tr>
	<tr align="right"> <td>10</td> <td> × </td> <td> 3</td> <td> = </td> <td> 30</td> </tr>
</table>

Zobrazený výsledek bude pak vypadat asi takhle:

08-SQLite editovat

Microframework lze rozšiřovat různými pluginy – jejich aktuální seznam je zde: List of available Plugins. Použití si ukážeme na příkladu pluginu pro manipulaci s databází SQLite:

Nejdřív si nainstalujeme řádkový interface k SQLite a příslušný plugin do Bottle:

sudo apt-get install sqlite3
sudo pip3 install bottle-sqlite

Pozor ale na Bottle/Problém/verze pluginu!

Potom si v řádkovém interface vytvořím a naplním nějakou databázi (samozřejmě i toto lze dělat z Bottle, ale pro jednoduchost si tu databázi teď připravíme předem):

$ sqlite3 test.db
SQLite version 3.8.2 2013-12-06 14:53:30
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table seznam (id INTEGER, name, number INTEGER);
sqlite> insert into seznam values (1, 'Adam', 101);
sqlite> insert into seznam values (2, 'Božena', 202);
sqlite> insert into seznam values (3, 'Cyril', 303);
sqlite> insert into seznam values (4, 'David', 404);
sqlite> select * from seznam;
1|Adam|101
2|Božena|202
3|Cyril|303
4|David|404
sqlite> 

Tím se nám do souboru test.db uložila jednoduchá databáze například telefonních linek, kterou se teď pokusíme pomocí Bottle zobrazit na Webu:

#!/usr/bin/env python3

from bottle import route, install, template, run
from bottle_sqlite import SQLitePlugin

install(SQLitePlugin(dbfile='./test.db'))

@route('/')
#def show():
def show(db):
    c = db.execute('SELECT * FROM seznam')
    rows = []
    while True:
        row = c.fetchone()
        if not row:
            break
        rows.append(row)
    return template ('seznam1', rows=rows)

run(host='localhost', port=8080, debug=True)

Ještě si musíme v podadresáři views vytvořit šablonu seznam1.tpl

<h1>Seznam</h1>

<table>
<%
for row in rows:
%>
	{{!'<tr> <td align="right">{:2}</td> <td align="left">{:10}</td> <td align="right">{:5}</td> </tr>'.format(row['id'], row['name'], row['number'])}}
% end
</table>


Po spuštění programu ./08-SQLite.pyobdržíme hlášku:

Bottle v0.12.8 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

a na URL http://localhost:8080/ uvidíme:

Seznam

1 Adam 101
2 Božena 202
3 Cyril 303
4 David 404


Podíváme-li se na zdrojový kód stránky, uvidíme:

<h1>Seznam</h1>

<table>
	<tr> <td align="right"> 1</td> <td align="left">Adam      </td> <td align="right">  101</td> </tr>
	<tr> <td align="right"> 2</td> <td align="left">Božena    </td> <td align="right">  202</td> </tr>
	<tr> <td align="right"> 3</td> <td align="left">Cyril     </td> <td align="right">  303</td> </tr>
	<tr> <td align="right"> 4</td> <td align="left">David     </td> <td align="right">  404</td> </tr>
</table>

Tak to má být!