Repository 32bit  Forum
Repository 64bit  Wiki

[how-to] sqlalchemy: eseguire una query

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.

[how-to] sqlalchemy: eseguire una query

Messaggioda absinthe » sab set 26, 2009 13:54

premessa

questo post nasce come modifica dell'originale (riportato sotto come quote). avendo trovato la soluzione, la posto sul forum sperando possa essere di aiuto. se gli amministratori lo riterranno utile possono anche inserire il thread in cima alla lista con una flag sticky. questo post non vuole essere una guida esaustiva su python o sqlalchemy: solo una dritta!
messaggio originale ha scritto:salve,

ho iniziato a smanettare un pò con python e sqlite3. sto sviluppando un'applicazione che dovrebbe accede ad un database creato "altrove e da qualcun altro". il db per adesso è in sqlite3 ma potrebbe migrare in qualsiasi altro tipo di sql (es. mysql). per astrarre il codice dal db e per evitare di imparare tutto sql (che non conosco) solo per alcune piccole query, ho deciso di interfacciare il codice python al db tramite sqlalchemy (lo so studire fa bene ma ho poco tempo :-).
ora il problema è che di fatto non riesco a capire come fare una query e accedere ai risultati. in particolare ho seguito i comandi di questo tutorial che mi consente di eseguire una query (qui senza filtri) e prenderne i risultati. ma una volta memorizzati in un oggetto python poi non so come analizzare il contenuto di tale oggetto!
l'esempio è qui riportato. nel caso seguente accedo ad una tabella chiamata 'room' che viene perfettamente caricata (ho fatto alcuni controlli sulla sua esistenza in uno stralcio di codice che non riporto):
{snip...}
a questo punto vorrei leggere result, ma anche controllando il tipo e cercando nell'api di sqlalchemy non ci ho capito nulla... qualcuno è pratico della cosa?! esiste un modo divero di approcciare il problema?!
{snip...}

quello che descriverò ora è un riassunto di ciò che ho capito leggendo vari docs su sqlalchemy. di fatto è tutto spiegato sul sito del toolkit ma mi ci è voluto un pochino per capire!

intro

sqlalchemy (d'ora in avanti s.a.) è un orm python molto potente e quindi complesso (a mio avviso). lo scopo di base di un orm è caricare una tabella di un database (di solito sql) e interfacciarla con un normale oggetto tipico della programmazione o-o. s.a. fa molto di più di questo (interfacciare più database tra loro astraendone le specifiche del dialetto sql ad esempio). di seguito io mi limiterò a spiegare come agganciare s.a. ad un file sqlite3 e visualizzare il contenuto di una tabella. nel caso presente, la tabella si chiama 'room' ed è costituita da quattro campi (oltre alla primary key): type, size, budget, speaker_model. la tabella e i campi derivano da un caso reale, la cui spiegazione esula da questo post: prendeteli per quello che sono.

componenti essenziali di s.a.

s.a. possiede 4 componenti fondamentali: engine, metadata, mapper e session.

engine
engine è il "motore" di s.a., il suo scopo è "agganciare" uno specifico database. nel caso presente ci agganceremo ad un database sqlite3 contenuto in un unico file chiamato karray08000. il codice python per fare questo è:
Codice: Seleziona tutto
import sqlalchemy as sqla

#sql server connection to an sqlite3 file named karray_08000
my_engine = sqla.create_engine('sqlite:///karray_08000', echo=True)

questo codice crea un engine chiamato my_engine che si collega al database suddetto. il parametro echo=True serve per veder visulizzato sulla console l'output sql generato da s.a.

metadata
metadata serve per caricare tutte le informazioi relative alle tabelle presenti in un dato db. dal momento che il db è collegato a s.a. tramite un engine, metadata non fa altro che fare un binding su tale engine per caricare informazioni su una o più tabelle. nel presente caso carichiamo le informazioni relative ad una tabella chiamata room.
Codice: Seleziona tutto
import sqlalchemy as sqla

#sql server connection to an sqlite3 file named karray_08000
my_engine = sqla.create_engine('sqlite:///karray_08000', echo=True)

#expose table struct and load data from db
my_meta = sqla.MetaData(bind=my_engine) #create and bind metadata
my_room = sqla.Table('room', my_meta, autoload=True) #load table contents
my_meta.create_all()  # issue CREATE statements for all tables

il codice utilizza my_engine per accedere alla tabella 'room'. i nostri metadati sono gestiti dall'istanza my_meta. tale oggetto è collegato (bind) al motore di s.a., autocarica la tabella chiamata 'room' e, tramite il metodo create_all esegue il caricamento effettivo dei metadati.

mapper
per poter analizzare il contenuto di una tabella occorre collegarla ad un oggetto: una classe python. questo oggetto non è altro che uno "specchio" della tabella stessa: i suoi membri saranno uguali a tutti i campi della tabella 'room', ad eccezione della primary key. l'oggetto è visto proprio come un "riflesso" in uno specchio, tanto che, tecnicamente, il collegamento oggetto-tabella è chiamato "riflessione della tabella". per riflettere 'room' occorre creare un erede di un oggetto di tipo object - questo definito in s.a.- e "mapparlo" sulla tabella 'room':
Codice: Seleziona tutto
import sqlalchemy as sqla
from sqlalchemy.orm import mapper #!!!! ho aggiunto l'include per il mapper

class a_room(object): #!!!! creo un oggetto che eredita object
    def __init__(self, type=0, budget=0, size=0, model=0):
       #definisco un membro per ogni campo di 'room'
        self.type = type
        self.size = size
        self.budget = budget
        self.speaker_model = model

#sql server connection to an sqlite3 file named karray_08000
my_engine = sqla.create_engine('sqlite:///karray_08000', echo=True)

#expose table struct and load data from db
my_meta = sqla.MetaData(bind=my_engine) #create and bind metadata
my_room = sqla.Table('room', my_meta, autoload=True) #load table contents
my_meta.create_all()  # issue CREATE statements for all tables

#!!!! mappo la tabella sull'oggetto
mapper(a_room, self.room)

la cosa importante da notare è che si mappa direttamente l'oggetto e non una sia istanza!

session
A questo punto il gioco è fatto! qualunque sia l'origine della tabella noi ce la possiamo dimenticare: lavoreremo solo con il suo riflesso! per poter eseguire qualunque attività sql è necessario istanziare un oggetto di tipo session -contenuto in s.a.-. tale oggetto consentirà di creare, elinimare e modificare tabelle o di eseguire delle query. ad esempio il codice seguente stampa tutti i record di 'room':
Codice: Seleziona tutto
import sqlalchemy as sqla
from sqlalchemy.orm import mapper
from sqlalchemy.orm import sessionmaker #!!!! ho aggiunto l'include per la session

class a_room(object):
    def __init__(self, type=0, budget=0, size=0, model=0):
        #definisco un membro per ogni campo di 'room'
        self.type = type
        self.size = size
        self.budget = budget
        self.speaker_model = model

#sql server connection to an sqlite3 file named karray_08000
my_engine = sqla.create_engine('sqlite:///karray_08000', echo=True)

#expose table struct and load data from db
my_meta = sqla.MetaData(bind=my_engine) #create and bind metadata
my_room = sqla.Table('room', my_meta, autoload=True) #load table contents
my_meta.create_all()  # issue CREATE statements for all tables

#mappo la tabella sull'oggetto
mapper(a_room, my_room)

#!!!! creo un istanza di uno oggetto sessione...
Session_obj = sessionmaker(bind=my_engine) #create, bind and instantiate a commit session
my_session = Session_obj()
#!!! ...e lo uso per elencare i contenuti della tabella 'room'
for t, b, s, m in my_session.query(a_room.type, a_room.budget, a_room.size, a_room.speaker_model):
    print(t + ',' + b + ',' + s + ',' + m)               

anche la sessione my_session deve essere collegata al motore (bind=my_engine). una volta fatto il binding, una query sarà semplicemente la chiamata al metodo 'query' dell'istanza my_session. Due note importanti che all'inizio mi erano sfuggite e mi hanno generato un pò di confusione:
1- occorre creare prima un oggetto con la funzione 'sessionmaker' e poi istanziarlo: la sessione è un'istanza di un oggetto!
2- le operazioni di una sessione sono eseguite su un oggetto python e non su una sua instanza (così come per il mapper)!

conclusioni

non ci sono conclusioni: occorre solo leggere bene le istruzioni degli sviluppatori :-P

ciao,
M
Avatar utente
absinthe
Iper Master
Iper Master
 
Messaggi: 2354
Iscritto il: sab mag 14, 2005 23:00
Località: Prato
Nome Cognome: Matteo Nunziati
Slackware: 12.1 - defunct
Kernel: 2.6.32-5-amd64
Desktop: gnome
Distribuzione: debian squeeze

Torna a Programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti

cron