Applicazioni Web in Python: Le Viste

Applicazioni web in Python Oggi proseguiamo il tutorial di sviluppo della nostra applicazione Pylons analizzando un’altro componente del modello di sviluppo MVC (vedi spiegazione in Applicazioni Web in Python: I Controller): le Viste. Analizzeremo in particolare uno dei template engine per Pylons chiamato Mako.

Il template engine

Le viste hanno il compito di prendere i dati elaborati dai controller e fornirli all’utente finale nel formato scelto (in genere una pagina html).
La creazione del formato finale viene semplificata dall’uso di template engine (letteralmente “motore di template”) che permettono di usare alcuni costrutti tipici dei linguaggi di programmazione all’interno del testo da formattare, in maniera simile a quanto avviene nel PHP, dove è possibile aprire in un qualsiasi punto della pagina html un tag e rendere dinamica la creazione dell’output.

Pylons rispetto ad altri framework python ha il vantaggio di essere molto flessibile nella scelta dei componenti da utilizzare e infatti abbiamo una vasta scelta di template engine per modellare le viste. La nostra scelta è stata di utilizzare i template Mako ma altre scelte possibili sono (per citarne solo alcune): Jinja2, Cheetah, Genshi, Tempita.

Mako

Mako è un template engine che prende spunto dalla maggior parte dei template engine elencati precedentemente ed è concettualmente (citando il sito ufficiale) un interprete python “incluso” all’interno delle pagine.

Mako precompila i suoi template in codice python, ottimizzando così le performance di interpretazione e la sua sintassi si dimostra molto flessibile, poiché permette di includere codice in linguaggio python all’interno dei suoi template mentre altri motori concorrenti offrono una sintassi completamente originale e che a volte non si dimostra sufficientemente flessibile quanto un vero linguaggio di programmazione.

Prendiamo l’esempio fornito dal sito ufficiale:

<table>
    % for row in rows:
        ${makerow(row)}
    % endfor
</table>


    <tr>
    % for name in row:
        <td>${name}</td>\
    % endfor
    </tr>

Il codice riportato presente già molte delle caratteristiche che rendono Mako particolarmente interessante: ereditarietà, embedding di codice python, blocchi.

Sintassi

Mako supporta 4 diversi tipi di inclusione di codice.

Codice python embedded

L’equivalente del linguaggio PHP, che ci permette di inserire un qualsiasi tipo di codice python nel template, consiste nell’uso dei tag speciali <% che equivale a <?php e %> che equivale a ?> come si può vedere nelle righe 2-4.

Cicli e controlli condizionali

Python è però un linguaggio privo di parentesi e quindi per utilizzare cicli e costrutti condizionali inframezzati a codice html, Mako offre la possibilità di definire, anche qui similarmente a PHP, l’inizio e la fine di tali blocchi di codice.
Iniziando una riga con % si può aprire/chiudere uno di questi costrutti, terminandoli con endfor, endif etc… (Vedi righe 6-8).

Stampa di variabili/funzioni

L’operazione più semplice è la stampa di una variabile nel template o la chiamata di una funzione con la sintassi ${variabile} e ${funzione()}, ma sono consentite anche elaborazioni di piccole espressioni, come ad esempio:

<h1>${title if title != '' else 'Titolo predefinito'}</h1>

La cosa interessante è che l’output è automaticamente (per impostazione di pylons) ripulito per l’inserimento all’interno di codice html, senza dover fare escaping manualmente, come invece avviene in PHP con la funzione htmlentities, ma questo non avviene nel caso di chiamate a funzioni Mako.

Blocchi e costrutti speciali

Mako inoltre supporta alcuni tag speciali, che come in XML possono essere self-closed e la loro sintassi è:

[...]

Nell’esempio vengono usati i tag inherit (linea 1) e def (linee 11-17). Per l’elenco completo e la loro funzione rimando alla documentazione ufficiale.

Ereditarietà

Una delle caratteristiche più interessanti di Mako è l’ereditarietà dei template. Nell’esempio vediamo alla riga 1 che il template eredita dal template base.html che non ci viene illustrato dal sito ufficiale, ma che potrebbe assomigliare a qualcosa di questo tipo:

<title>${self.title()}</title>
  
  
    ${self.body()}
  



  Prova

In questo template ${self.title()} viene utilizzato per stampare il contenuto del blocco di nome title(), che può però essere ridefinito nei template figli se lo volessero, mentre ${self.body()} è un valore speciale che corrisponde all’intero contenuto del blocco figlio e che ci permette così di separare la costruzione della pagina html in template separati per strati.

Richiamare un template dai controller

Abbiamo visto la sintassi dei template, ma come li utilizziamo dall’interno dei nostri controller pylons?
L’uso è semplice e pylons ci semplifica il lavoro preimpostando tutta una serie di parametri di Mako e questo per noi significa che ci basta chiamare la funzione render(nometemplate) per ottenere l’output che ci serve.

Riprendiamo il controller dall’articolo precedente:

class HelloController(BaseController):
    def world(self):
        return render('/template.html')

Semplice no? E’ importante ricordarsi che render vuole sempre percorsi assoluti rispetto alla cartella [applicazione]/templates per i template, quindi specificando “/template.html”, Mako ci fornirà l’output del file [applicazione]/templates/template.html

Come fare, infine, a passare dati dal controller al template? Per questo pylons ci fornisce una variabile di contesto di nome c alla quale possiamo associare i dati che servono al template. c ha inoltre la proprietà speciale di restituire una stringa vuota se si prova a richiedere un valore non definito, evitando facili eccezioni nei nostri template.

Esempio hello.py:

class HelloController(BaseController):
    def world(self):
        c.name = 'World'
        return render('/template.html')

template.html:

<h1>Hello ${c.name}!</h1>

Conclusione

Questo articolo ha fornito una buona panoramica per iniziare a utilizzare i template Mako, ma ci sarebbe ancora molto, troppo per questa sede, da dire. La documentazione ufficiale è comunque molto esauriente e completa e fornisce anche esempi per la maggior parte delle funzionalità.

Nel prossimo articolo tratteremo i modelli Elixir per interagire col database.