---
title: Le SQL avec SQLite3
author: 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**](https://www.sqlite.org/index.html) 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

```python {.numberLines}
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).

```python {.numberLines}
import sqlite3

connection = sqlite3.connect("intro.sqlite3", autocommit=True)
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 :

```python {.numberLines}
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 :

```python {.numberLines}
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} :

```python {.numberLines}
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 : Les [ORM]{.naming}

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]{.naming}). 
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](https://www.sqlalchemy.org/)
- [Peewee](http://docs.peewee-orm.com/en/latest/)
- [Pony ORM](https://docs.ponyorm.org/toc.html)
- [Django ORM](https://docs.djangoproject.com/fr/3.2/topics/db/queries/) (framework web)

----

## Bibliothèques Python compatibles DB API 2.0 :

- MySQL : `pip install mysql-connector-python`{.shell} ([doc](https://dev.mysql.com/doc/connector-python/en/))
- PostgreSQL : `pip install psycopg`{.shell} ([doc](https://www.psycopg.org/docs/))
- SQL Server : `pip install pymssql`{.shell} ([doc](https://pymssql.readthedocs.io/en/stable/))
- Oracle : `pip install cx_Oracle`{.shell} ([doc](https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html))

----

## 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 :

1. Cliquez sur `File`, `Settings`, puis la section `Plugins`.
2. Cliquez sur l'onglet `Marketplace`
3. Juste en-dessous de l'onglet `Marketplace`, dans le champ de recherche, saisissez "Database"
4. Vous devriez voir `Database Navigator` apparaître dans les résultats.
5. En regard de ce résultat, cliquez sur `Install`.
6. 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 :

![Afficher DB Browser](assets/images/database-show-db-browser.png)

----

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.

1. Dans l'onglet `Connections` et le sous-onglet `Database`,
2. Choisissez un nom à votre connexion. Il vous servira juste visuellement
3. Dans le tableau de l'option `Database files`, cliquez sur `sqlite.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.
4. Dans l'onglet `Connections`, cliquez le sous-onglet `Details`, puis :
5. Réduisez toutes les options `Idle time...` à `1`
6. Décochez `Connect automatically`
7. 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)

----

![Onglet Database](assets/images/database-configure-connection.png)

----

![Onglet Details](assets/images/database-configure-connection-settings.png)
