Python

Introduzione a SQLAlchemy

Introduzione a SQLAlchemy
LT
Luca Terribili
Autore

La sua capacità di astrarre le operazioni SQL in costrutti Python consente agli sviluppatori di concentrarsi sulla logica di business, riducendo gli errori tipici della scrittura manuale di query. Inoltre, SQLAlchemy offre sia un ORM (Object‑Relational Mapping) che un livello di espressione SQL chiamato Core, fornendo la flessibilità necessaria per chi desidera un controllo più fine sulle operazioni di database.

Nel seguito, esploreremo passo passo le caratteristiche fondamentali di SQLAlchemy: dall’installazione, alla definizione dei modelli, alle query di base, fino alla gestione delle relazioni e delle operazioni CRUD. Ogni sezione è corredata da esempi pratici pronti per essere inseriti in un progetto reale, così da facilitare l’apprendimento e l’implementazione immediata.

Che cos'è SQLAlchemy e perché usarlo?

SQLAlchemy offre una sintassi intuitiva per esprimere operazioni sui dati, trasformando le istruzioni SQL in costrutti Python facili da leggere e da mantenere. Grazie a questa astrazione, gli sviluppatori possono scrivere codice più pulito, riducendo la complessità delle query tradizionali.

Oltre all’ORM, il framework mette a disposizione il livello Core, che consente di costruire statement SQL con un controllo più dettagliato, ideale per chi ha esigenze avanzate di ottimizzazione o di utilizzo di funzioni specifiche del database.

La flessibilità di SQLAlchemy lo rende compatibile con una vasta gamma di database relazionali, permettendo di migrare o supportare più backend senza riscrivere il codice di accesso ai dati. Per questo motivo, molte applicazioni web, API e script di analisi dei dati scelgono SQLAlchemy come strumento di riferimento.

Installazione e configurazione di base

Per avviare un progetto con SQLAlchemy, il primo passo è installare il pacchetto tramite pip. L’installazione è rapida e non richiede dipendenze aggiuntive per il motore di base:

pip install sqlalchemy

Se il gestore di pacchetti non è ancora presente, è possibile attivarlo con python -m ensurepip --upgrade. Dopo l’installazione, il modulo è pronto per essere importato e per creare l’engine, ovvero l’oggetto che gestisce la connessione al database.

L’engine richiede una connection string che specifica il tipo di DB e le credenziali di accesso. Ecco alcuni esempi tipici:

## SQLite (file locale)
engine = create_engine('sqlite:///mydatabase.db')

## MySQL
engine = create_engine('mysql://username:password@localhost/mydatabase')

Una volta ottenuto l’engine, è possibile aprire connessioni, creare sessioni o eseguire query direttamente, offrendo un punto di partenza solido per qualsiasi progetto.

Creazione del primo modello

I modelli rappresentano le tabelle del database mediante classi Python. Si definiscono ereditando da declarative_base() e dichiarando le colonne come attributi, ottenendo così una mappatura chiara tra oggetti e record.

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)

Il modello sopra genera una tabella users con le colonne id, name e email. Per materializzare la tabella nel database basta eseguire:

engine = create_engine('sqlite:///mydatabase.db')
Base.metadata.create_all(engine)

A questo punto è possibile inserire, leggere e modificare record usando le sessioni di SQLAlchemy, con la sicurezza di avere una struttura dati ben definita e tipizzata.

Query di base con SQLAlchemy

Le operazioni di lettura richiedono una sessione, creata tramite sessionmaker. La sessione gestisce il ciclo di vita delle transazioni e consente di eseguire query in modo molto simile a come si farebbe in puro SQL.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine('postgresql://username:password@localhost/db_name')
Session = sessionmaker(bind=engine)
session = Session()

Supponiamo di avere già il modello User. Per ottenere tutti gli utenti dal database possiamo scrivere:

users = session.query(User).all()
for u in users:
    print(f"{u.name} {u.email}")

Il metodo filter consente di aggiungere criteri specifici alle query, per esempio per selezionare gli utenti con indirizzo email appartenente a un dominio particolare:

m_users = session.query(User).filter(User.email.like('%@example.com')).all()
for u in m_users:
    print(u.name)

SQLAlchemy supporta inoltre ordinamenti, join, aggregazioni e molte altre operazioni avanzate, ma queste basi dimostrano già quanto sia semplice passare da un modello Python a una query SQL eseguita sul database.

Relazioni tra modelli

Le relazioni permettono di collegare tabelle tra loro, rappresentando associazioni uno‑a‑uno, uno‑a‑molti o molti‑a‑molti. Grazie a queste definizioni, è possibile navigare tra le entità senza scrivere manualmente le clausole JOIN.

Ecco un esempio di rapporto uno‑a‑molti tra User e Order:

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    orders = relationship('Order', back_populates='user')

class Order(Base):
    __tablename__ = 'orders'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    date = Column(DateTime)
    user = relationship('User', back_populates='orders')

La proprietà orders in User restituisce una lista di oggetti Order associati, mentre order.user fornisce l’utente proprietario dell’ordine. Questo approccio semplifica la navigazione tra le entità e mantiene il codice coerente e manutenibile.

Inoltre, è possibile personalizzare il comportamento delle relazioni, ad esempio impostando il lazy loading per caricare i dati solo quando necessario, contribuendo a migliorare le performance delle applicazioni.

Esecuzione di operazioni CRUD

Creazione di un nuovo record

new_user = User(name='John Doe', email='johndoe@example.com')
session.add(new_user)
session.commit()

Aggiungere un nuovo record è semplice: si crea un'istanza del modello, la si aggiunge alla sessione e si esegue il commit per rendere permanente l’inserimento.

Lettura di record esistenti

all_users = session.query(User).all()          # tutti gli utenti
first_user = session.query(User).first()      # primo utente
filtered = session.query(User).filter(User.email.like('%@example.com')).all()  # filtro per dominio email

Le query di lettura possono essere affinate con filtri, ordinamenti e limiti, consentendo di recuperare esattamente i dati di interesse.

Aggiornamento di un record esistente

user = session.query(User).get(1)
user.email = 'new_email@example.com'
session.commit()

Per modificare un record basta recuperarlo, aggiornare gli attributi desiderati e confermare la transazione con commit.

Eliminazione di un record esistente

user = session.query(User).get(1)
session.delete(user)
session.commit()

L’eliminazione segue lo stesso schema delle operazioni precedenti: si recupera l’oggetto, lo si rimuove dalla sessione e si conferma l’operazione.

Approfondire SQLAlchemy: risorse e conclusioni

SQLAlchemy è ormai uno standard de‑facto per la gestione dei database in Python. La documentazione ufficiale rappresenta il punto di riferimento più completo, con guide all’installazione, tutorial passo‑a‑passo e riferimenti API dettagliati. Oltre a questa risorsa, esistono numerosi tutorial, corsi video e repository su GitHub che mostrano casi d’uso reali, dalle applicazioni Flask alle pipeline di data‑science.

Entrare a far parte di community come Stack Overflow, i forum di SQLAlchemy o i gruppi Discord può fornire supporto rapido e suggerimenti pratici. Partecipare a discussioni open‑source è inoltre un ottimo modo per tenersi aggiornati sulle nuove versioni, sulle best practice e per contribuire al futuro del progetto.

Con le basi illustrate in questo articolo, sei pronto a integrare SQLAlchemy nei tuoi progetti e a sfruttare la potenza di un ORM flessibile e affidabile. Buona programmazione!