Home > flask, python > Flask (parte 4): views e templates

Flask (parte 4): views e templates

30 Giugno 2015

Quando un client (ad es. un web browser) manda una richiesta al web server, questi
la gira all’istanza “app” di Flask che deve riconoscere l’URL richiesta ed
eseguire il codice ad essa associato.
Questo avviene tramite funzioni dette views, che vengono associate ad un determinato url,
per mezzo del decoratore @app.route.

Se lanciassimo il server ora, con il comando:

python manage.py runserver
(venv) ...>python manage.py runserver
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

visitando la pagina indicataci http://127.0.0.1:5000/
ci troveremmo di fronte ad una bella pagina di errore

ValueError: View function did not return a response

Questo perchè non esiste ancora nessuna view associata alla route (“/”) del sito,
per fare questo, apriamo il file app/main/views.py

from flask import render_template
from . import main

@main.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')

creata la view, dobbiamo creare anche la template, gestite da Jinja2.
Creiamo il file app/templates/index.html

<h1>Welcome to Fantamanager!</h1>

ora lanciando il server e visitando la pagina, dovremmo vedere il nostro messaggio di benvenuto.

E se volessimo passare un argomento alla template?
la funzione render_template, accetta argomenti da passare alla template ad es. (app/main/views.py):

from flask import render_template
from . import main

@main.route('/', methods=['GET', 'POST'])
def index():
    name = "bancaldo"
    return render_template('index.html', name=name)

All’interno della template, gli argomenti si inseriscono tramite la doppia graffa:

<h1>{{ name }}, welcome to Fantamanager!</h1>

Ora creiamo una view che ci dia delle informazioni prelevate dal database, creiamo un po’ di users:

python manage.py shell
>>> for name in ("pippo", "pluto", "paperino"):
...     u = User(username=name, email="{}@example.com".format(name))
...     db.session.add(u)
...
>>> db.session.commit()
>>> User.query.all()
[<User u'pippo'>, <User u'pluto'>, <User u'paperino'>]

Ora vorrei una pagina che mi elencasse tutti gli users, quindi andiamo sul file
app/main/views.py e creiamo la views. Per prelavare dati dal database, ovviamente
abbiamo bisogno di importare l’oggetto User da models.py quindi:

from ..models import User
#...
@main.route('/users', methods=['GET', 'POST'])
def users():
    users = User.query.all()
    return render_template('users.html', users=users)

Creiamo la template relativa agli users, app/templates/users.html
Jinja2 oltre a passare argomenti, utilizza strutture di controllo e in questo caso
utilizzeremo un ciclo for:

<ul>
{% for user in users %}
	<li>{{ user.username }} mail to: {{ user.email}}</li>
{% endfor %}
</ul>

se rilanciamo il server e visitiamo la pagina http://127.0.0.1:5000/users
troviamo la nostra lista users.

Grazie a Jinja2 le template possono utilizzare l’ereditarietà ovvero è possibile
creare una template base.html:

<html>

<head>
    {% block head %}
        <title>{% block title %}{% endblock %} - Fantamanager</title>
    {% endblock %}
</head>

<body>
    {% block body %}
    {% endblock %}
</body>

</html>

ed estenderla, solo nei blocchi interessati, nelle singole templates.
In questo modo il codice verrà sempre modificato in un unico punto e non
su tutte le singole templates. Nel caso di prima, la template derivante sarà:

{% extends "base.html" %}

{% block title %}Users{% endblock %}

{% block body %}
    <ul>
    {% for user in users %}
	<li>{{ user.username }} mail to: {{ user.email}}</li>
    {% endfor %}
    </ul>
{% endblock %}

Adesso vediamo lo stile, che come ci siamo resi conto dal nostro browser,
è veramente scarno.
Per ottenere qualcosa di più appetibile visivamente, possiamo integrare il
framework Bootstrap, derivato da twitter. Essendo questa un’estensione di
Flask, sarà molto semplice installarla.
Sempre da venv, installiamo l’estensione:

C:\fantamanager>venv\Scripts\activate
(venv) C:\fantamanager>pip install flask-bootstrap
Collecting flask-bootstrap
...
Successfully installed flask-bootstrap-3.3.5.2

Ora lo registriamo nel nostro costruttore (app/__init__.py):

#...
from flask.ext.bootstrap import Bootstrap
#...


bootstrap = Bootstrap()
#...


def create_app(config_name):
    #...
    bootstrap.init_app(app)
    #...

    return app

Dopo l’installazione, sarà disponibile una template base.html di
bootstrap, dalla quale derivare tutte le altre.
Il nuovo codice della template users.html diventerà:

{% extends "bootstrap/base.html" %}

{% block title %}Users{% endblock %}

{% block navbar %}
	<div class="navbar navbar-inverse" role="navigation">
		<div class="container">
			<div class="navbar-header">
				<button type="button" class="navbar-toggle"
				data-toggle="collapse" data-target=".navbar-collapse">
					<span class="sr-only">Toggle navigation</span>
					<span class="icon-bar"></span>
					<span class="icon-bar"></span>
					<span class="icon-bar"></span>
				</button>
				<a class="navbar-brand" href="/">Home</a>
				</div>
		</div>
	</div>
{% endblock %}

{% block content %}
	<div class="container">
		<div class="page-header">
			<ul>
			{% for user in users %}
			<li>{{ user.username }} mail to: {{ user.email}}</li>
			{% endfor %}
			</ul>
		</div>
	</div>
{% endblock %}

Index diventerà:

{% extends "bootstrap/base.html" %}
{% block title %}Users{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
  <div class="container">
    <div class="navbar-header">
	<button type="button" class="navbar-toggle"
	 data-toggle="collapse" data-target=".navbar-collapse">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
	  <span class="icon-bar"></span>
	  <span class="icon-bar"></span>
	</button><a class="navbar-brand" href="/users">Users</a>
    </div>
  </div>
</div>
{% endblock %}

{% block content %}
  <h1>{{ name }}, welcome to Fantamanager!</h1>
{% endblock %}

Le navigation bar contengono già i link delle rispettive pagine di esempio alle
quali reindirizzare il browser.

Ultima cosa da sapere.
Se volessimo catturare un argomento dall’url immesso dal client e generare una vista personalizzata?
Bisogna catturare l’argomento desiderato nella vista, racchiudendolo tra <>, es.

from flask import render_template, redirect, url_for
from ..models import User
from . import main


@main.route('/', methods=['GET'])
def index():
    return render_template('index.html')

@main.route('/users', methods=['GET'])
def users():
    allusers = User.query.all()
    return render_template('users.html', users=allusers)

@main.route('/user/<name>', methods=['GET'])
def user(name):
    user = User.query.filter_by(username=name.lower()).first()
    if not user:
        return redirect(url_for('.index'))
    return render_template('user.html', user=user)

e la template user.html sarà:

{% extends "bootstrap/base.html" %}

{% block title %}Users{% endblock %}

{% block navbar %}
	<div class="navbar navbar-inverse" role="navigation">
		<div class="container">
			<div class="navbar-header">
				<button type="button" class="navbar-toggle"
				data-toggle="collapse" data-target=".navbar-collapse">
					<span class="sr-only">Toggle navigation</span>
					<span class="icon-bar"></span>
					<span class="icon-bar"></span>
					<span class="icon-bar"></span>
				</button>
				<a class="navbar-brand" href="/">Home</a>
				</div>
		</div>
	</div>
{% endblock %}

{% block content %}
  <div class="container">
    <h1>Welcome {{ user.username }}</h1>
    <div class="page-header">
      <ul>username: {{ user.username }}</ul>
      <ul>email: {{ user.email }}</ul>
    </div>
  </div>
{% endblock %}

index.html va poi rivista, poichè nell’ultmia versione importava l’argomento “name” che ora non serve più.

articolo successivo:
Flask (parte 5): password security

articoli precedenti:
Flask (parte 1): virtualenv
Flask (parte 2): struttura progetto complesso
Flask (parte 3): database

link utili:
“Flask Web Development” di Miguel Grinberg, fondamentale per calarsi nel mondo di Flask.
Altri link fondamentali:
Flask sito ufficiale
il blog dell’autore (Flask mega tutorial)

Categorie:flask, python Tag: ,
I commenti sono chiusi.