Cesco
Cesco

Il mio blog personale

Francesco
Author

Share


Tags


Appunti su Peewee

FrancescoFrancesco

Ecco alcune dritte per lavorare con Peewee, un simpatico ORM creato da Charles Leifer molto più semplice da gestire del tanto osannato SQLAlchemy.

Come creo o mi collego ad database SQLite esistente ?

Per collegarsi ad un database SQLite esistente, o per crearne uno nuovo devo scrivere:

db = peewee.SqliteDatabase("<nome file del database>")  

Nel caso il file indicato non dovesse esistere, peewee provvederà automaticamente a creare un nuovo database

Ad esempio, per accedere al database contenuto nel file miodatabase.sqlite dovrò scrivere:

db = peewee.SqliteDatabase("miodatabase.sqlite")  

Come definisco le tabelle del mio database ?

Devo creare una nuova classe avendo cura di farla derivare dalla classe peewee.Model, così:

class Utente(peewee.Model):

    id = peewee.PrimaryKeyField()
    nome = peewee.CharField(max_length=140)
    email = peewee.CharField(max_length=140)

class Meta:

    database = db

è importante che la classe che creo per definire il modello contenga a sua volta la classe meta, che serve a spiegare a peewee che la classe/tabella appena descritta fa parte del database indicato nella proprietà database (nel nostro caso database = db)

Solitamente l'autore di peewee consiglia di scrivere la definizione delle tabelle creando prima una propria classe base in cui viene indicato il database di appartenenza, e poi far derivare le altre classi con la definizione delle tabelle da questa classe base, in questo modo:

class ModelloBase(peewee.Model):

    class Meta:

        database = db


class Utente(ModelloBase):

    id = peewee.PrimaryKeyField()
    nome = peewee.CharField(max_length=140)
    email = peewee.CharField(max_length=140)

DA NOTARE: Per convenzione, il nome di una classe che contiene la definizione di una tabella è sempre scritto al singolare. Ad esempio creiamo la classe "Utente" anzichè la classe "Utenti", oppure la classe "Ordine" anzichè la classe "Ordini".


Come posso creare un nuovo record all'interno di una tabella ?

Devo creare una nuova istanza della classe che contiene la tabella in cui voglio inserire i dati, compilare i campi e quindi invocare il metodo save() per salvare le modifiche:

nuovo_utente = Utente()  
nuovo_utente.nome = "Mario Rossi"  
nuovo_utente.email = "mario.rossi@gmail.com"  
nuovo_utente.save()  

E se volessi modificare un record esistente ?

Se nella tabella esiste già un record con l'indice indicato, il record viene aggiornato con i nuovi dati. Altrimenti viene creato un nuovo record.

Ad esempio se scrivo:

print(Utente.select().count())  
# Stampa come numero di record nella tabella: 0

nuovo_utente = Utente()  
nuovo_utente.id = 1  
nuovo_utente.nome = "Mario Rossi"  
nuovo_utente.email = "mario.rossi@gmail.com"  
nuovo_utente.save()  
print(Utente.select().count())  
# Stampa come numero di record nella tabella: 1

nuovo_utente = Utente()  
nuovo_utente.id = 1  
nuovo_utente.nome = "Giulio Verdi"  
nuovo_utente.email = "giulioverdi@hotmail.it"  
nuovo_utente.save()  
print(Utente.select().count())  
# Stampa come numero di record nella tabella sempre 1

Come posso eseguire una query su di una tabella ?

Per eseguire una query scrivo <classe modello della tabella>.select(). Ad esempio, per ottenere tutti gli utenti nella tabella precedente scrivo:

risultato_query = Utente.select()  

posso anche richiedere di ricevere solo determinati campi della tabella, inserendoli nei parametri del metodo select() così:

# Tutte le email presenti nella tabella
risultato_query = Utente.select(Utente.email)  

 Come posso filtrare una query ?

Posso filtrarla agganciando al metodo select() il metodo where() in questa maniera:

# Cerca l'utente "Mario Rossi"
risultato_query = Utente.select().where(Utente.nome == "Mario Rossi")  

Se so già che la query di cui ho bisogno mi restituirà un solo record, come nel caso precedente, posso anche utilizzare questo comando del tutto analogo ma più breve e conciso:

# Cerca sempre l'utente "Mario Rossi"
risultato_query = Utente.get(Utente.nome == "Mario Rossi")  

Una volta eseguita una query come posso scorrere fra i risultati ?

Ad esempio così:

# Cerca tutti gli utenti
risultato = Utente.select()

for elemento in risultato:  
    print(elemento.nome)
    print(elemento.email)

Come posso cancellare un record dalla tabella ?

Ad esempio eseguendo una query per ottenere il record ed utilizzando il metodo delete_instance():

# Cerca l'utente Mario Rossi
condannato = Utente.get(Utente.nome == "Mario Rossi")

# Lo cancella
condannato.delete_instance()  

E se volessi cancellare più utenti alla volta ?

Posso utilizzare il metodo delete()

# Cancella tutti gli utenti che non hanno registrato un'email
query = Utente.delete().where(Utente.email == "")

# Siccome è potenzialmente letale (per i record della tabella),
# devo espressamente dire a peewee di eseguire la query
query.execute()  

Nel caso di una tabella che contiene campi esterni legati ad un'altra tabella
(pensa ad esempio a una tabella fornitori ed a una tabella ordini dai fornitori che al suo interno ha un campo codice_fornitore che fa riferimento alla prima
tabella), posso anche utilizzare delete_instance(recursive=True) che nel
nostro esempio cancellerà un fornitore e poi si andrà a pescare dall'altra
tabella tutti gli ordini effettuati al fornitore e li cancellerà automaticamente.

(Vedi maggiori informazioni sulle tabelle con relazioni nella prossima domanda)


Cosa devo fare per avere due tabelle relazionate l'una con l'altra

Devo utilizzare un campo peewee.ForeignKeyField(<Classe/Tabella correlata>, related_name='<Nome del campo "virtuale" nella tabella correlata>')

Ad esempio, se ho una tabella Evento che contiene

  1. Degli eventi a cui posso partecipare prenotandomi (Tabella "Evento")
  2. Una lista di prenotati con nome, email ed evento prenotato (Tabella "Prenotato")

posso scrivere:

class ModelloBase(pee.Model):

    class Meta:
        database = db


class Evento(ModelloBase):

    id = pee.PrimaryKeyField()
    titolo = pee.CharField(max_length=140)
    descrizione = pee.TextField()
    data = pee.DateField()
    prezzo = pee.FloatField()
    acquistabile = pee.BooleanField(default=True)


class Prenotato(ModelloBase):

    id = pee.PrimaryKeyField()
    nome = pee.CharField(max_length=140)
    email = pee.CharField(max_length=140)
    evento_prenotato = pee.ForeignKeyField(Evento, related_name='prenotati')

In questo caso andando a fare una query su Evento troverò a disposizione anche il campo "virtuale" chiamato prenotati che conterrà l'elenco di tutte le persone
che hanno prenotato quel particolare evento. Ad esempio:

risultato = app.Evento.get(app.Evento.id == 1)

# Ora scrive quello che ha trovato

print(risultato.nome)  # Nome dell'evento  
print(risultato.prenotati[0].nome)

# ...oppure...

for prenotato in risultato.prenotati  
    print(prenotato.nome)
Francesco
Author

Francesco

Comments