NSI · Terminale
Bases de données : interroger une base SQLite avec Python
Découvrez comment manipuler et interroger une base de données relationnelle SQLite en Python avec le module standard sqlite3 (connexion, curseurs, requêtes paramétrées, transactions, prévention des injections SQL et annales du Bac NSI).
Interroger une base SQLite avec Python
Introduction
Dans les chapitres précédents, nous avons appris à concevoir un modèle relationnel et à écrire des requêtes SQL pour interroger une base de données.
Dans une application réelle (site web, application mobile, logiciel de gestion, analyse de données), les requêtes SQL ne sont pas exécutées manuellement par un humain dans une console, mais de manière automatisée par un programme informatique.
Python dispose nativement dans sa bibliothèque standard d'un module dédié : `sqlite3`. Aucun outil externe ni installation supplémentaire (pip) n'est nécessaire.
Schéma de fonctionnement
Le programme Python communique avec la base de données via le module sqlite3 :
- Programme Python (`script.py`) : Prépare et transmet la requête SQL au moteur SQLite à l'aide de l'objet curseur (
curseur.execute(...)). - Moteur SQLite (`sqlite3`) : Analyse la requête, effectue les opérations de lecture ou d'écriture dans le fichier de base de données (
bibliotheque.db). - Retour des données : Le moteur SQLite renvoie les enregistrements sous forme de structures de données Python (
curseur.fetchall()renvoie une liste de tuples).
Le cycle de communication avec une base de données
Toute interaction entre Python et SQLite suit systématiquement 5 étapes fondamentales :
- Importer le module
sqlite3. - Établir une connexion vers le fichier de base de données (
sqlite3.connect). - Créer un curseur pour exécuter les instructions SQL (
connexion.cursor()). - Exécuter les requêtes SQL (
curseur.execute()) et récupérer les résultats (fetchall(),fetchone()). - Valider les modifications (
connexion.commit()) et fermer la connexion (connexion.close()).
1. Établir la connexion à la base de données
La fonction sqlite3.connect(nom_fichier) ouvre la connexion avec la base de données. Si le fichier n'existe pas encore sur votre disque, SQLite le crée automatiquement.
Base de données en mémoire vive
Pour des tests unitaires ou des exercices rapides sans créer de fichier sur le disque dur, vous pouvez utiliser la base spéciale en mémoire :
2. Le rôle fondamental du Curseur
Le curseur est l'objet intermédiaire qui transmet vos commandes SQL au SGBD et stocke temporairement les résultats renvoyés par la base.
Le curseur fournit les méthodes suivantes :
curseur.execute(requete_sql, [parametres]): exécute une seule requête SQL.curseur.executemany(requete_sql, liste_de_tuples): exécute la même requête avec plusieurs jeux de valeurs.curseur.fetchall(): renvoie toutes les lignes du résultat sous forme d'une liste de tuples.curseur.fetchone(): renvoie la première ligne (un tuple) ouNonesi aucun résultat.
3. Créer une table et insérer des données
A. Création de table (DDL)
B. Insertion de données & Rôle crucial de commit()
Lorsqu'on effectue une opération d'écriture (INSERT, UPDATE, DELETE), les modifications restent temporaires dans une transaction. Pour les enregistrer définitivement dans le fichier, il faut appeler connexion.commit().
Attention : Piège classique au Bac NSI
Si vous oubliez d'appeler connexion.commit(), les données insérées ou modifiées seront perdues dès la fermeture du script (Rollback automatique) !
4. Interroger la base et récupérer les enregistrements
A. Récupérer tous les résultats avec fetchall()
La méthode curseur.fetchall() renvoie une liste de tuples. Chaque tuple correspond à un enregistrement (ligne) de la table.
Sortie console :
B. Récupérer une ligne unique avec fetchone()
Lorsque la requête ne doit renvoyer qu'un seul résultat (par exemple une recherche par clé primaire ou une fonction d'agrégation COUNT), on utilise curseur.fetchone().
C. Parcours itératif direct du curseur (Économie de mémoire)
Pour de très grandes bases de données contenant des millions de lignes, charger toute la table en mémoire avec fetchall() peut saturer la RAM. On peut itérer directement sur l'objet curseur :
5. Requêtes paramétrées et Sécurité (Injections SQL)
C'est l'un des points les plus importants au programme du Bac NSI.
Danger : la concaténation de chaînes (f-strings)
Supposons qu'un utilisateur saisisse le nom d'un auteur via un formulaire web ou un input() :
Si un pirate saisit comme nom d'auteur :
La requête exécutée devient :
Comme la condition '1'='1' est toujours vraie, la base de données renverra l'intégralité des données, contournant toute authentification ou sécurité. Un pirate pourrait même injecter '; DROP TABLE LIVRES; -- pour détruire la table !
Bonne pratique : les requêtes préparées paramétrées avec ?
Pour se protéger contre les injections SQL, on utilise le symbole réservé `?` (placeholder) et on transmet les valeurs dans un tuple en second paramètre de execute() :
Le driver SQLite se charge d'échapper correctement les caractères spéciaux et d'associer le bon type de données, rendant toute injection SQL impossible.
6. Accès par nom de colonne avec sqlite3.Row
Par défaut, SQLite renvoie les lignes sous forme de simples tuples indexés par des entiers (ligne[0], ligne[1]). Pour rendre le code beaucoup plus lisible, on peut configurer connexion.row_factory :
7. Exemple complet d'architecture modulaire
Voici un module Python complet et professionnel démontrant les bonnes pratiques de programmation en Terminale NSI (fonctions pures, gestion des transactions, requêtes paramétrées) :
Fiche de Révision Synthétique (Bac NSI)
| Méthode / Concept | Rôle & Syntaxe |
|---|---|
sqlite3.connect(fichier) | Ouvre ou crée la base de données. |
con.cursor() | Crée le curseur d'exécution des requêtes. |
cur.execute(sql, tuple_params) | Exécute une requête SQL de manière sécurisée. |
cur.executemany(sql, liste_tuples) | Exécute une insertion ou mise à jour par lot. |
cur.fetchall() | Récupère tous les enregistrements (liste de tuples). |
cur.fetchone() | Récupère le premier enregistrement ou None. |
con.commit() | Valide et enregistre de façon permanente les modifications. |
con.close() | Ferme la connexion et libère les verrous de fichier. |
? (Placeholder) | Empêche formellement les failles de sécurité par injection SQL. |
Exercices du Baccalauréat à réviser
Les interactions entre bases de données relationnelles et scripts Python font l'objet d'exercices réguliers au Bac NSI :
- Sujet 2024 - Groupe 2 (Jour 2) - Exercice 3 : Conception de requêtes SQL et manipulation de résultats en Python (
sqlite3, parcours de tuples et calculs de moyennes). - Sujet 2023 - Métropole (Jour 1) - Exercice 3 : Schéma relationnel, cardinalités, requêtes de mise à jour et écriture de fonctions Python sécurisées avec requêtes paramétrées.
- Sujet 2022 - Centres Étrangers - Exercice 4 : Analyse de vulnérabilités d'injection SQL et conversion de requêtes concaténées vers des requêtes préparées.
Avez-vous compris et assimilé ce cours ?
+50 XPÉtudiez le contenu activement pendant au moins 45 secondes pour pouvoir débloquer la validation au mérite.
