Pubblicato su www.programmazione.it a maggio 2003
In questo articolo vedremo come poter utilizzare il database server MySQL con il mio linguaggio preferito: Python. Prima di tutto, per chi non conosce Python, vi consiglio di leggere gli altri articoli di questa sezione. L'applicazione consiste in un grossolano mini-gestionale per un magazzino orto-frutticolo, una semplice tabella dove andremo ad archiviare la nostra frutta con nome e quantità.
In questo articolo darò per scontato il fatto che abbiate una minima esperienza con un DBMS come MySQL e con il linguaggio SQL. Detto questo passiamo all'azione: per connetterci MySQL avremo bisogno di un modulo DB API 2 compatibile.
Scarichiamo il modulo dal sito http://sourceforge.net/projects/mysql-python, una volta scaricato andremo ad installarlo: Se state lavorando su piattaforma Windows scaricatevi il pacchetto .exe che vi istallerà in automatico il modulo. Se lavorate con Linux o uno Unix in generale allora scaricatevi il MySQL-python-0.9.2.tar.gz, ed eseguite i seguenti comandi.
$ tar xfz MySQL-python-0.9.2.tar.gz $ cd MySQL-python-0.9.2 $ python setup.py build $ su # python setup.py install
Terminata l'installazione possiamo cominciare a parlare della nostra applicazione:
In Python fino a poco tempo fa, la gestione dei database era un miscuglio di moduli scritti da diverse persone in tutto il mondo che non avevano una uniformità tale da poter semplificare la scrittura di codice. Per semplificare l'accesso ai database relazionali è stata realizzata un' API che è di riferimento per tutti quelli che dovranno scrivere un modulo per l'accesso ad un database relazionale. Attualmente siamo arrivati alla versione 2.0. Il modulo che andremo ad utilizzare è basato su questa ultima versione dell' API.
L'API mette le basi per le chiamate al modulo dell'accesso al db. Ad esempio: se volete collegarvi ad Oracle o a MySQL il metodo per farlo si chiama sempre connect(). Questo vi permette di scrivere codice portatile su altre piattaforme database
La lista dei metodi più importanti di un modulo sono:
connect(parametri...) - metodo che crea l'oggetto connessione al db e ne restituisce l'istanza.apilevel() - restituisce una stringa con il numero della versione della specifica DB API.threadsafety() - Un intero per specificare se l'interfaccia può essere condivisa da altri thread.paramstyle - Costante stringa per indicare quale carattere utilizzare per la formattazione delle query SQL.Warning() - Eccezione che viene lanciata quando ci sono dei problemi trascurabili come il troncamento di dati troppo lunghi in fase di inserimento.Error() - Eccezione che viene lanciata in casi di errore.Di seguito vi elenco i metodi dell'oggetto Connessione:
close() - chiude la connessione con il database.commit() - conferma tutte le modifiche apportate al db, disponibile solamente su database di tipi transazionale come ad esempio Oracle e PostgreSQL, (MySQL ultimamente supporta le transazioni solamente con tabelle di tipo InnoDB e non su quelle stabdard MyISAM).rollback() - revoca tutte le modifiche apportate al db, disponibile solamente su database di tipi transazionale come ad esempio Oracle, PostgreSQL.., (MySQL ultimamente supporta le transazioni solamente con tabelle di tipo InnoDB e non su quelle stabdard MyISAM).cursor() - restituisce un cursore dove poter lanciare SELECT, INSERT, UPDATE, store procedure ecc...
Per qualsiasi operazione sul DB dobbiamo creare un oggetto Cursor partendo dall'oggetto Connessione con il metodo cursor(). L'oggetto Cursor creato avrà questi metodi e attributi:
rowcount - attributo che contiene il numero totale di record che ha restituito l'ultima chiamata al metodo execute().callproc(nomeprocedura [,parametri]) - chiama una store procedure (disponibile solamente se il database supporta le store procedures).close() - chiude il cursore.execute(operazione [,parametri]) - prepara, esegue una operazione sul database, utilizzando il carattere di formattazione definito nell'attributo paramstyle..Questi sono i metodi e gli attributi principali di una interfaccia DB API 2 compatibile.
Se l'installazione è andata a buon fine siete pronti per collegarvi a MySQL. Lanciamo l'interprete Python, in una shell, con il seguente comando:
python
Dovrebbe comparire una schermata del genere:
Python 2.2 (#1, 07/14/02, 23:25:09) [GCC Apple cpp-precomp 6.14] on darwin Type "help", "copyright", "credits", or "license" for more information. >>>
importiamo il modulo con questo comando:
>>>import MySQLdb
se non si verifica nessuna eccezione allora il modulo è stato installato senza problemi. A questo punto creiamo la nostra connessione. Il codice per la connessione è il seguente:
>>>conn = MySQLdb.connect(host="localhost", user="root", passwd="", db="DBprova" )
Abbiamo creato la connessione ad un server MySQL che sta girando sulla stessa macchina del nostro script, sulla porta standard 3306. Ci siamo collegati come utente root e senza password.
Gli altri parametri per questo metodo sono:
port - numero di porta TCP dove lavora il database server.unix_socket - locazione del socket Unix, da utilizzare con collegamenti locali.compress - indica se si deve utilizzare un protocollo compresso, per default non è compresso.connect_timeout - tempo in secondi, si chiude la connessione se un?operazione sul db non si conclude entro questo tempo.unicode - se è settato, i campi di tipo Char e Varchar sono restituiti con codifica Unicode.
Modificando opportunamente questi parametri possiamo collegarci a qualsiasi database in qualsiasi parte
del mondo ed eseguire comandi SQL con pochissime righe di Python.
Una volta creata la connessione per eseguire qualsiasi operazione, abbiamo bisogno di un cursore.
Allora andiamo a creare un oggetto di tipo cursore:
>>>cursore = conn.cursor()
cursore è l'istanza di un oggetto Cursor che ci permetterà di eseguire operazioni e ottenere dati dalle tabelle.
Supponiamo di avere una tabella che si chiama frutta nel nostro database Dbprova, e che contenga la lista della frutta nel magazzino.
Vogliamo sapere quale frutta c'è in magazzino:
>>>cursore.execute('SELECT * FROM frutta')
>>>cursore.fetchall()
>>>((1, 'Mele', 50), (2, 'Pere', 25), (3, 'Banane', 60))
Abbiamo eseguito la query e il risultato è una tuple che contiene tante tuple per ogni record che abbiamo richiesto. In questo caso tutti i record presenti nella tabella frutta. Notate che i dati contenuti nelle tuple sono di tipo diverso, ci sono interi e stringhe perchè i tipi di dati SQL vengono, nel limite delle possibilità, tradotti in tipi equivalenti di Python.
Se iteriamo in un ciclo for i risultati, possiamo formattarli in colonne:
>>>for record in cursore.fetchall(): ... print '%d\t%s\t%d' % (record[0], record[1], record[2]) ... 1 Mele 50 2 Pere 25 3 Banane 60 >>>
Ecco fatto!, in pochi passi stiamo utilizzando uno dei più potenti e veloci database al mondo da una sessione dell'interprete Python. Utilizzando sempre il metodo execute potete creare query anche di una certa complessità e farvi restituire i risultati in un batter d'occhio!. Ora vediamo come poter utilizzare execute per preparare l'SQL per inserimenti e modifiche. Prendiamo come esempio sempre la nostra tabella frutta. Dobbiamo inserire un nuovo frutto, ci sono arrivati da poco in magazzino i Pompelmi.
frutta :
cursore.execute('INSERT INTO frutta (nome, quantita) VALUES(%s, %s)',
('Pompelmi', 10)
)
Abbiamo inserito un nuovo frutto: il pompelmo con quantità 10 pezzi. Verifichiamo se è andato tutto bene eseguendo la query di prima:
>>>cursore.execute('SELECT * FROM frutta')
>>>for record in cursore.fetchall():
... print '%d\t%s\t%d' % (record[0], record[1], record[2])
...
1 Mele 50
2 Pere 25
3 Banane 60
4 Pompelmo 10
>>>
se prendiamo in esame l'utilizzo del metodo execute nell'ultimo esempio vi renderete conto che ho passato due parametri al metodo, la stringa SQL di preparazione e una tuple con i dati da inserire.
Questa metodo risulta molto potente per il trattamento veloce dei dati da inserire, senza dover trattare la stringa SQL con sostituzioni di caratteri speciali.
Con questa modalità di lavoro non dovrete preoccuparvi se il vostro dato è una stringa, un intero, una data o qualsiasi altra cosa. La query SQL completa verrà creata dal metodo execute prima di essere eseguita sul database.
Notate i caratteri utilizzati per la preparazione del codice SQL: %s, questo è quello che viene definito nell'attributo paramstyle dell'interfaccia. (noi non l'abbiamo definito e ci ritroviamo con %s che è quello predefinito)
Con il tempo la quantità della frutta in magazzino diminuisce sempre di più e dobbiamo aggiornare costantemente il nostro database. Allora andremo a modificare le quantità dei nostri frutti:
frutta :
cursore.execute('UPDATE frutta SET quantita=%s WHERE nome=\'Pere\'', (5))
cursore.execute('UPDATE frutta SET quantita=%s WHERE nome=\'Mele\'', (3))
cursore.execute('UPDATE frutta SET quantita=%s WHERE nome=\'Banane\'', (6))
cursore.execute('UPDATE frutta SET quantita=%s WHERE nome=\'Pompelmi\'', (7))
Andiamo nuovamente a verificare se la modifica è andata a buon fine:
>>>cursore.execute('SELECT * FROM frutta')
>>>for record in cursore.fetchall():
... print '%d\t%s\t%d' % (record[0], record[1], record[2])
...
1 Mele 3
2 Pere 5
3 Banane 6
4 Pompelmo 7
>>>
Con poche righe di codice abbiamo creato un mini-gestionale per il nostro magazzino, con la stessa facilità potrete creare applicazioni che richiedono anche un certa complessità.
Se siete programmatori Python e avete la necessità di interfacciarvi con un database MySQL, questo articolo vi permetterà di gestire i vostri dati in maniera semplice e veloce. MySQL attualmente è il database open source più diffuso al mondo. Probabilmente avete avuto a che fare già con questo database. Io vi ho illustrato come poter sfruttarlo anche con Python. Personalmente ho utilizzato parecchie volte questa accoppiata di tecnologie per piccoli software come mini-gestionali oppure come script per automatizzare alcune operazioni su database come backup oppure sincronizzazione di tabelle SQL oppure per l'importazione in tabelle di dati formattati in file CSV.