10 KiB
title, author
title | author |
---|---|
Le SQL avec SQLite3 | Steve Kossouho |
Premiers pas en SQL avec SQLite3
DBAPI c'est quoi ?
Python propose une API unifiée standardisée pour accéder à des bases de données SQL (Structured Query Language), nommée DBAPI. Les objets et méthodes ont toujours les mêmes noms et le même usage. Il existe plusieurs bibliothèques compatibles pour accéder à des systèmes différents. La bibliothèque standard de Python propose une API compatible pour SQLite3.
SQLite3 est un moteur de bases de données relationnelles au format fichier, facile à mettre en place, et adapté pour des logiciels de bureau (ex. Firefox l'utilise). Il n'est pas adapté pour être utilisé dans une application web en production, car il ne gère pas les rôles et droits, ni ne tolère les multiples connexions (en écriture notamment).
Manipuler une base avec DBAPI
Pour travailler sur notre première base de données, nous allons découper l'exemple en quatre étapes.
Étape 1 : Se connecter à la base
import sqlite3
connection = sqlite3.connect("intro.sqlite3", isolation_level=None)
connection.close()
Crée un nouveau fichier de base de données SQLite3, pour le moment vide.
Étape 2 : Créer un schéma de base
On brode sur l'exemple précédent pour créer une nouvelle table. Cette table ne possède pas de contrainte particulière et autorise à enregistrer des doublons (mêmes prénom, nom et âge).
import sqlite3
connection = sqlite3.connect("intro.sqlite3", isolation_level=None)
cursor = connection.cursor() # cet objet est utilisé pour envoyer des requêtes
cursor.execute("""
CREATE TABLE IF NOT EXISTS person (
id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
nom varchar(30) NOT NULL,
prenom varchar(20) NOT NULL,
age int unsigned NOT NULL
)""")
connection.close()
Étape 3 : Ajouter des données
On ajoute ensuite quelques données dans notre nouvelle table :
import sqlite3
# Requête d'insertion utilisant la notation QMark (protection contre injections)
PERSON_INSERT_QUERY = "INSERT OR IGNORE INTO person (id, nom, prenom, age) VALUES (NULL, ?, ?, ?)"
connection = sqlite3.connect("intro.sqlite3", isolation_level=None)
cursor = connection.cursor()
...
cursor.execute(PERSON_INSERT_QUERY, ("Bouquet", "Carole", 63))
cursor.execute(PERSON_INSERT_QUERY, ("Connery", "Sean", 80))
cursor.execute(PERSON_INSERT_QUERY, ("Trintignant", "Jean-Louis", 53))
connection.close()
Étape 4 : Requêter et parcourir des résultats
Comme pour les fichiers texte dans lesquels nous pouvons naviguer dans les lignes via une boucle for
{.python},
exécuter une commande SQL destinée à renvoyer des résultats autorise à parcourir l'objet de type Cursor
{.python} via une boucle for
{.python} pour récupérer des résultats :
import sqlite3
connection = sqlite3.connect("intro.sqlite3", isolation_level=None)
cursor = connection.cursor()
...
# Exécuter une requête pour retrouver des données
cursor.execute("SELECT * FROM person WHERE age > 50")
for result in cursor: # s'arrête automatiquement quand il n'y a plus de résultat
print(result) # result est toujours un tuple correspondant à un résultat
connection.close()
Bonus : Récupérer des résultats sous forme de dictionnaires
Il est possible de configurer l'objet de connexion SQLite3 pour récupérer des objets de type sqlite3.Row
{.python} :
import sqlite3
connection = sqlite3.connect("demo.sqlite", isolation_level=None)
# Configure la connexion pour que les requêtes renvoient des objets Row
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
...
cursor.execute("SELECT * FROM person WHERE age BETWEEN 20 AND 40")
for result in cursor: # type: sqlite3.Row
print(result, dict(result))
connection.close()
Les objets de type sqlite3.Row
{.python} sont utilisables comme des dictionnaires, et permettent ainsi d'extraire des résultats en utilisant les noms des colonnes. Ils sont aussi convertibles directement en dictionnaires.
Hors-programme : Requêtes universelles avec les ORMs
C'est bien d'envoyer du SQL à une base de données, mais le problème du standard SQL, c'est que tous les systèmes de gestion de bases de données ne gèrent pas toujours le SQL de la même façon; certains proposent leur propre syntaxe ou ne prennent pas en charge une partie du standard, etc…
Sur un projet de taille moyenne, et même de taille modeste, si vous écrivez tout votre code SQL à la main, basculer d'un SGBDR à un autre (par exemple pour un passage en production) nécessitera très probablement de retoucher ou d'adapter vos requêtes.
Ce problème est, entre autres questionnements, à l'origine de l'existence des ORMs (Object Relational Mapper
).
Ce sont des bibliothèques qui offrent une abstraction de la base de données et la remplacent par
l'écriture de code, non plus en SQL, mais dans votre langage orienté objet préféré,
pour représenter des schémas et manipuler vos données.
Les ORMs font généralement usage des concepts suivants :
Objet | Correspond à... |
---|---|
Classe Modèle | Table de la base de données |
Attribut de classe | Colonne d'une table |
Instance de Modèle | Ligne d'une table de la base de données |
En plus de cela, le même code peut être utilisé pour basculer d'un SGBD à un autre (s'il est pris en charge par l'ORM).
Exemples d'ORMs Python connus :
- SQLAlchemy
- Peewee
- Pony ORM
- Django ORM (framework web)
Bonus : Petite explication sur isolation_level
Dans notre premier slide contenant du code, nous avons défini un argument facultatif à la fonction connect
, nommé
isolation_level
. Celui-ci permet de définir le niveau d'isolation des commandes SQL que l'on envoie.
Si l'on passe la valeur None
{.python} à cet argument, l'auto-commit est activé, ce qui signifie que nous n'avons plus besoin
d'appeler manuellement commit()
{.python} lorsqu'on souhaite persister nos modifications. Ceci est normalement le comportement
par défaut pour toute bibliothèque DBAPI, mais pour une raison inconnue, cela n'est pas le cas pour sqlite
. Le bug sera corrigé
dans Python 3.12.
En temps normal, si nous n'avions pas précisé ce paramètre :
- Ouvrir la connexion (sans autocommit)
connection.execute()
{.python} → ouvre une transactionconnection.execute()
{.python}connection.execute()
{.python}- Aucune modification n'est persistée tant qu'on n'appelle pas
connection.commit()
{.python}
Le fait de devoir cnx.commit()
{.python} par défaut n'est pas spécialement intuitif, notamment
lorsqu'on débute en bases de données...
Grâce à notre paramètre isolation_level
, le comportement est plus intuitif par défaut :
- Ouvrir la connexion (avec autocommit)
connection.execute()
{.python} → modification immédiateconnection.execute()
{.python} → modification immédiateconnection.execute("BEGIN")
{.python} → Ouverture explicite d'une transactionconnection.execute()
{.python} → modification non persistéeconnection.execute("COMMIT")
{.python} → ferme la transaction et applique les modifications si possible
Bibliothèques Python compatibles DB API 2.0 :
- MySQL :
pip install mysql-connector-python
{.shell} (doc) - PostgreSQL :
pip install psycopg
{.shell} (doc) - SQL Server :
pip install pymssql
{.shell} (doc) - Oracle :
pip install cx_Oracle
{.shell} (doc)
Navigateur de bases de données intégré à Pycharm
Vous pouvez naviguer dans vos bases de données graphiquement dans PyCharm grâce à un plugin de l'IDE, nommé Database Navigator.
Pour l'installer :
- Cliquez sur
File
,Settings
, puis la sectionPlugins
. - Cliquez sur l'onglet
Marketplace
- Juste en-dessous de l'onglet
Marketplace
, dans le champ de recherche, saisissez "Database" - Vous devriez voir
Database Navigator
apparaître dans les résultats. - En regard de ce résultat, cliquez sur
Install
. - Si l'installation fonctionne, cliquez en regard du résultat sur
Restart IDE
pour redémarrer PyCharm.
Configurer DB Navigator
Si vous venez d'installer le plugin, vous devez révéler le panneau de l'extension. Le plus simple est d'utiliser le menu de PyCharm pour le trouver :
Vous pouvez déplacer le panneau avec un clic droit sur sa barre de titre, puis en cliquant sur Move
.
Cela vous permettra de ne pas masquer le panneau de projet lorsque vous travaillez sur votre base de données.
Configurer une base de données
Dans le panneau DB Browser, cliquez sur l'icône d'ajout pour créer une configuration, puis choisissez SQLite.
- Dans l'onglet
Connections
et le sous-ongletDatabase
, - Choisissez un nom à votre connexion. Il vous servira juste visuellement
- Dans le tableau de l'option
Database files
, cliquez sursqlite.db
, puis cliquez sur le bouton qui apparaît au bout de la ligne de texte, afin de choisir le bon fichier de base de données SQLite à surveiller. - Dans l'onglet
Connections
, cliquez le sous-ongletDetails
, puis : - Réduisez toutes les options
Idle time...
à1
- Décochez
Connect automatically
- Terminez la configuration en cliquant le bouton
OK
.
Vous pouvez ensuite voir dans le panneau DB Browser
que votre connexion est prête, dans une arborescence.
Cliquez sur le nœud principal de l'arborescence, puis cliquez sur Connect
(il faut se connecter à la base pour pouvoir en explorer le contenu)