Applicazioni Web in Python: La struttura

Proseguiamo la creazione della nostra applicazione Pylons. Nell’articolo precedente eravamo arrivati alla creazione dell’ambiente e della base della nostra applicazione col comando:

$ paster create --template shabti_auth myapp

Paster si occuperà di creare, in base alle regole specificate dal template scelto (in questo caso shabti_auth), le cartelle e i file necessari alla nostra applicazione.

Durante la creazione del filesystem inoltre paster ci chiede che template engine vogliamo utilizzare e se vogliamo avere una configurazione pronta per l’uso di SQLAlchemy. Scegliamo l’opzione predefinita per il template engine, ovvero Mako, mentre rispondiamo “True” alla richiesta di SQLAlchemy.

Vediamo quindi cosa ha creato paster:

$ find myapp -type d
myapp
myapp/docs
myapp/myapp
myapp/myapp/config
myapp/myapp/controllers
myapp/myapp/forms
myapp/myapp/forms/validators
myapp/myapp/lib
myapp/myapp/lib/auth
myapp/myapp/model
myapp/myapp/public
myapp/myapp/templates
myapp/myapp/tests
myapp/myapp/tests/functional
myapp/myapp/tests/unit
myapp/myapp.egg-info
$ ls -l myapp
totale 44
-rw-r--r--  1 user user 1624 17 mag 17.57 development.ini
drwxr-xr-x  2 user user    8 17 mag 17.57 docs
-rw-r--r--  1 user user 9716 17 mag 17.57 ez_setup.py
-rw-r--r--  1 user user  110 17 mag 17.57 MANIFEST.in
drwxr-xr-x 10 user user   80 17 mag 17.57 myapp
drwxr-xr-x  2 user user   64 17 mag 17.57 myapp.egg-info
-rw-r--r--  1 user user  953 17 mag 17.57 README.txt
-rw-r--r--  1 user user  537 17 mag 17.57 setup.cfg
-rw-r--r--  1 user user 1009 17 mag 17.57 setup.py
-rw-r--r--  1 user user  621 17 mag 17.57 test.ini

Il file più interessante nella cartella principale è development.ini, che rappresenta la configurazione che la nostra applicazione dovrà usare durante lo sviluppo. A sviluppo terminato dovremo ricordarci di usare un ini per la produzione (di solito production.ini) con delle impostazioni diverse. Il vantaggio dell’avere configurazioni separate sta nel poter attivare la modalità di debug durante lo sviluppo senza esporre funzionalità potenzialmente pericolose all’utente finale e il poter specificare un diverso database da usare, piuttosto che una porta di rete diversa, etc…

Diamo quindi un’occhiata al file in questione:

#
# myapp - Pylons development environment configuration
#
# The %(here)s variable will be replaced with the parent directory of this file
#
[DEFAULT]
debug = true
# Uncomment and replace with the address which should receive any error reports
#email_to = you@yourdomain.com
smtp_server = localhost
error_email_from = paste@localhost

[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 5000

[app:main]
use = egg:myapp
full_stack = true
static_files = true

cache_dir = %(here)s/data
beaker.session.key = myapp
beaker.session.secret = somesecret

# If you'd like to fine-tune the individual locations of the cache data dirs
# for the Cache data, or the Session saves, un-comment the desired settings
# here:
#beaker.cache.data_dir = %(here)s/data/cache
#beaker.session.data_dir = %(here)s/data/sessions

# SQLAlchemy database URL
sqlalchemy.url = sqlite:///%(here)s/development.db

# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
# Debug mode will enable the interactive debugging tool, allowing ANYONE to
# execute malicious code after an exception is raised.
#set debug = false

# Logging configuration
[loggers]
keys = root, routes, myapp, sqlalchemy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_routes]
level = INFO
handlers =
qualname = routes.middleware
# "level = DEBUG" logs the route matched and routing variables.

[logger_myapp]
level = DEBUG
handlers =
qualname = myapp

[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither.  (Recommended for production systems.)

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s
datefmt = %H:%M:%S

Come possiamo vedere è attiva la modalità di debug (debug = true) ed è possibile specificare dove ricevere le email ogni qual volta si verifica un errore nella nostra applicazione specificando i valori di error_email_to, smtp_server e error_email_from. Questa opzione in realtà è molto più utile una volta che l’applicazione verrà eseguita in produzione.

Nella sezione server:main leggiamo che l’applicazione sarà raggiungibile in localhost sulla porta 5000, quindi facendo puntare il browser a http://localhost:5000 (vedremo più avanti).

Una prima configurazione da modificare la troviamo in app:main, dove è meglio cambiare beaker.session.secret, ovvero una chiave segreta che verrà usata per cifrare i dati di sessione. E’ sufficiente inserire una stringa casuale. Inoltre consiglio di scommentare le righe beaker.cache.data_dir e beaker.session.data_dir, in modo da separare i dati di cache e sessioni, il che può essere comodo quando si vuole cancellare la cache senza però azzerare anche le sessioni.

Ed infine troviamo sqlalchemy.url che specifica all’ORM come connettersi al database, che in questo caso è un database sqlite3 definito come file development.db nella cartella del progetto.

Nell’elenco dei file però il file development.db non esiste ancora. Per crearlo dobbiamo inizializzare l’applicazione col comando:

$ paster setup-app development.ini

Che in pratica utilizza la configurazione in development.ini per inizializzare l’applicazione (non necessariamente solo il database) eseguendo lo script myapp/web_setup.py.

Shabti ha già definito per noi alcune entità del database per cui possiamo provare subito a eseguire il comando e creare così il database con alcune tabelle e dei dati di prova.

Fatto questo possiamo finalmente lanciare la nostra applicazione e visualizzarne il risultato nel nostro browser all’indirizzo http://localhost:5000 col comando:

$ paster serve --reload development.ini
Starting subprocess with file monitor
Starting server in PID 27760.
serving on http://127.0.0.1:5000

L’opzione reload specificata fa si che paster ricarichi l’applicazione ogni qual volta venga rilevata una modifica ai file, risparmiandoci un po’ di fatica.

Nel prossimo articolo analizzeremo modelli e controller.