Flask
- Hello World
- Flask omalle koneelle
- Debuggaus
- Reititys ja osoitteet
- Templatet
- request
- Edelleenohjaus
- response
- session
- Lisätietoa
Flask on mikrosovelluskehys jolla voidaan tehdä web-sovelluksia.
Flask perustuu WerkZeug WSGI-kirjastoon ja Jinja2-kirjastoon
WSGI (Web Server Gateway Interface) on Pythonin oma rajapinta web-sovellusten toteuttamiseen. Vrt. CGI
Flaskin toiminta on helppo oppia Quickstart-tutoriaalista. Tässä materiaalissa käydään pääpiirteissään lapi Quickstart-tutoriaalin sisältö.
Hello World
Flaskin asennus- ja käyttötapa riippuu ympäristöstä. Jyväskylän yliopiston users.jyu.fi-palvelimella Flaskia on käytettävä CGI-sovelluksena. Tämä ei ole kovin tehokas tapa mutta riittää hyvin Flaskilla harjoitteluun. Flaskissa on mukana oma pieni www-palvelin jota voi käyttää perusasioiden testailuun.
Minimaalinen Flask-sovellus
# importoidaan Flask-luokka ja luodaan siitä samantien esiintymä from flask import Flask app = Flask(__name__) # Kerrotaan Flaskille mitä osoitetta seuraava funktio vastaa @app.route('/') def hello_world(): return 'Hello World!' # Jos ajetaan suoraan komentoriviltä niin käynnistetään Flaskin oma webbipalvelin if __name__ == '__main__': # asetetaan debug-moodi päälle. Ei saa pitää päällä tuotantokäytössä app.debug = True app.run()
Flaskia aloitellessa muistakaa users.jyu.fi:ssä kaikki temput mitä vaadittiin, että cgi-ohjelma lähtee toimimaan:
- oltava cgi-bin-kansiossa
- ryhmän oltava users
- suoritusoikeus ja lukuoikeus ryhmällä ja muilla
- cgi-ohjelmaan ei saa olla kirjoitusoikeutta ryhmällä ja muilla
- Myöskään samaan kansioon ei saa olla kirjoitusoikeutta ryhmällä ja muilla
- Flask hoitaa itse http-otsakkeet
- Mitään ei saa printata flask-funktiosta vaan vain ja ainoastaan voidaan palauttaa return-lauseessa yksi merkkijono
Flask omalle koneelle
Asenna Anaconda (Python 2.7), jonka mukana tulee myös Flask.
Tämän jälkeen riittää, kun käynnistää oman sovelluksen komennolla
python oma.py
ja voi kokeilla selaimella osoitteessa:
http://127.0.0.1:5000/tai
http://localhost:5000/
Nyt saa myös selkeät virheilmoitukset suoraan selaimeen, koska Flaskin debug-tila toimii omalla koneella.
Halavassa / jalavassa tämä ei onnistu, koska Flaskia ei niistä löydy eikä tule ennen kuin koneet päivitetään samaan käyttisversioon kuin users.jyu.fi. Yliopiston mikroluokkien koneisiin on osaan asennettuna Anaconda.
Lopullinen sovellus pitää yleensä saada toimimaan muualla kuin omalla koneella ja toiminnallisuudessa voi olla eroja esim. tiedostopolut voivat olla erilaisia. Debuggaus on kuitenkin huomattavasti helpompaa omalla koneella. Jos on W:-asema verkkolevynä niin voi suoraan sieltä ajaa sovellustaan oman koneen Flaskilla ja testailla samaan aikaan myös users.jyu.fin kautta.
Debuggaus
Sitten kun flask-sovellus lähtee toimimaan niin virheiden debuggaus on haastavaa, koska users.jyu.fi:ssä ei toimi flaskin oma debug-tila. Ohjelman kaatuessa syntaksivirheeseen tai ajonaikaiseen virheeseen on tuloksena vain internal server error. cgitb-kirjasto ei auta.
Täytyy itse logata virheet. Seuraava tekee lokitiedoston kansioon '../hidden/'. Korjaa polku oikeaksi:
import logging logging.basicConfig(filename=os.path.abspath('../hidden/flask.log'),level=logging.DEBUG) logging.debug("Tänne mitä haluaa lokiin kirjoittaa")
Älä kirjoita lokia cgi-bin-kansioon tai sen alikansioihin!. Tämä ei toimi.
Jotta lokista olisi iloa on käytettävä try..exceptiä. Nappaa exceptillä kiinni mahdolliset virheet ja dumppaa virheilmoitus lokiin:
try: # sqlite haluaa absoluuttisen polun con = sqlite3.connect(os.path.abspath('../hidden/resepti')) except Exception as e: logging.debug("Kanta ei aukea") # sqliten antama virheilmoitus: logging.debug(str(e))
Lokin sisältöä voitte seurailla helpoiten ottamalla pääteyhteyden halavaan ja käyttämällä tail-komentoa:
tail -f flask.log
Tämä kyttää koko ajan tiedoston sisältöä ja näyttää heti sinne tulevat uudet rivit.
Reititys ja osoitteet
Flask käyttää Pythonin decorator-funktiota määrittelemään mikä osoite viittaa mihinkäkin funktioon.
# vastaa osoitteeseen /hello @app.route('/hello') def hello(): return 'Hello World'
Osoitteissa voi olla myös muuttujia. Osoitteessa oleva muuttuja annetaan funktiolle parametrina.
@app.route('/user/<username>') def show_user_profile(username): # show the user profile for that user return 'User %s' % username
Muuttujille on olemassa myös pari convertteria. Nämä eivät kelpuuta vääränlaisia arvoja
int | Kokonaisluvut |
---|---|
float | Liukuluvut |
path | Polku, joka kelpuuttaa myös /-merkit |
@app.route('/post/<int:post_id>') def show_post(post_id): # show the post with the given id, the id is an integer return 'Post %d' % post_id
route-dekoraattorilla kerrotaan myös mitä HTTP-metodeja kyseinen funktio ymmärtää:
# kelpuutetaan sekä GET että POST -metodit. GET on aina oletuksena kelvollinen @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': do_the_login() else: show_the_login_form()
Samaan funktioon voi osoittaa useita erilaisia reittejä:
# vastaa osoitteeseen /hello @app.route('/hello/<name>') @app.route('/hello') def hello(name=None): if name: return 'Hello ' + name return 'Hello World'
Osoitteet
Flaskin käyttämissä osoitteissa on merkitystä käyttääkö osoitteen lopussa /-merkkiä vai ei:
# tätä voi kutsua osoitteilla /projects ja /projects/. Ensimmäinen ohjaantuu jälkimmäiseen @app.route('/projects/') def projects(): return 'The project page' # Tätä voi käyttää vain muodossa /about @app.route('/about') def about(): return 'The about page'
Osoitteita voi muodostaa url_for-funktiolla:
# seuraava rivi käskee Flaskin suorittaa komennot kuin www-selainpyynnön tapauksessa vaikka # sovellusta oikeasti testataan komentoriviltä with app.test_request_context(): print url_for('projects') # tulostaa /projects/ print url_for('about') # tulostaa /about
Kannattaa käyttää url_for-funktiota ennemmin kuin hardkoodata osoitteet kaikkialle.
Templatet
Flask käyttää Jinja2-templateja aivan samaan tapaan kuin aiemmin on opittu CGI-ohjelman yhteydessä.
from flask import render_template @app.route('/hello/') def hello(name=None): return render_template('hello.html', name=name)
Templateja etsitään "templates"-alikansiosta, joka sijaitsee samassa kansiossa kuin sovelluksesi.
Templateissa voit käyttää render_template-kutsussa vietyjen parametrien lisäksi request-, session- ja g-objekteja.
request
request-objekti sisältää www-selaimelta lähetetyt tiedot ja muut http-pyyntöön liittyvät tiedot. Request-objekti tulee Werkzeug-kirjaston kautta.
from flask import request
Request-objektin tärkeimmät ominaisuudet ovat:
- request.args GET-metodilla eli URLissa tulleet parametrit
- request.base_url Sivun polku ilman querystring-osaa eli ?-merkin jälkeistä osuutta
- request.charset Pyynnössä käytetty merkistö
- request.cookies Mahdolliset evästeet dict-muodossa
- request.files Mahdolliset tiedostot
- request.form POST-metodilla tulleet parametrit
- request.full_path Koko sivun polku mukaanlukien querystring
- request.method Käytetty metodi (GET, POST jne.)
- request.path Polku
- request.query_string Pyynnön querystring-osa
- request.remote_addr Asiakkaan IP-osoite
- request.remote_user Asiakkaan mahdollinen käyttäjätunnus
- request.values request.args ja request.form sisältö yhdistettynä
Lomakeparametreja käsiteltäessä on otettava kiinni KeyError, joka tulee jos pyydettyä parametriä ei löydykkään:
@app.route('/login', methods=['POST', 'GET']) def login(): if request.method == 'POST': try: if valid_login(request.form['username'], request.form['password']): return log_the_user_in(request.form['username']) else: error = 'Invalid username/password' except KeyError: error = 'Invalid form' # the code below is executed if the request method # was GET or the credentials were invalid return render_template('login.html', error=error)
Voidaan käyttää myös samoja metodeja kuin cgi.fieldstoragen yhteydessä:
# toisena parametrina voidaan antaa oletusarvo jota käytetään jos usernamea ei ole annettu username = request.form.get("username", "") # listat toimivat kuten cgi.fieldstoragen kanssa lista = request.form.getlist("arvo") # palauttaa aina listan. Jos arvoja ei ole niin lista on tyhjä
Edelleenohjaus
Edelleenohjaus hoituu redirect-funktiolla:
from flask import abort, redirect, url_for @app.route('/') def index(): return redirect(url_for('login'))
response
Flask tekee automaattisesti response-tyyppisen objektin näkymän palauttamasta merkkijonosta. Response-objekti sisältää kaiken tarpeellisen jotta voidaan muodostaa sopiva vastaus selaimelle. Jos tarvii muokata vastausta niin muodostettu response-objekti pitää erikseen ottaa talteen, muokata ja vasta sitten palauttaa:
from flask import request, response, make_response @app.route('/') def index(): # 200 tarkoittaa http-protokollan vastausta jossa kaikki OK. Tarvittaessa # voidaan tehdä esim. oma virhesivu (404) etc. resp = make_response(render_template('index.html'), 200) # keksitään oma http-otsake resp.headers['X-Foobar'] = 'Testi' # Määritetään merkistö resp.charset = "UTF-8" # Määritetään mimetyyppi resp.mimetype = "text/html" return resp @app.route('/text') def text(): resp = make_response("foobar. palautetaan pelkkää tekstiä", 200) # Määritetään merkistö resp.charset = "UTF-8" # Määritetään mimetyyppi resp.mimetype = "text/plain" return resp
Käyttäjien kommentit