GERBELOTBARILLON.COM

Parce qu'il faut toujours un commencement...

Python permet nativement d'interagir avec des systèmes de bases de données. Celui que nous utiliserons est MySQL. Cela sera probablement différent avec un autre SGBDR mais nous resterons concentrés sur celui-ci.

Pour commencer, il faut installer le connecteur de bases de données nommé mysql-connector-python avec l'outil pip.

python -m pip install mysql-connector-python

Ce module dispose d'une méthode connect() qui retourne un objet représentant la connexion au système de bases de données. Vous devez fournir le nom du serveur, l'utilisateur et son mot de passe de connexion ainsi que le nom de la base de données à utiliser.

import mysql.connector

db = mysql.connector.connect(
    host="localhost",
    user="login",
    password="mot_de_passe",
    database="demo_python"
)

# faire quelque chose d'utile avec la connexion

db.close()

Une fois la connexion ouverte, la communication avec la base de données s'effectue par l'intermédiaire d'un curseur, qui s'obtient par la méthode cursor() obtenue sur la connexion. Une fois le traitement terminé, il est fortement conseillé de fermer le curseur. Un curseur se comporte comme un gestionnaire de ressources et il est donc possible de l'utiliser avec la syntaxe with de python.

Toutes les requêtes s'exécutent sur le curseur en appelant la méthode execute().

Sélection de données

Pour récupérer des données de la base de données, il faut utiliser une requête SQL de type select sur le curseur et d'appeler la méthode fetchall() pour récupérer une liste de n-uplets.

request = "select id, nom, score, date_inscription, actif from utilisateur"

   with db.cursor() as c:
      c.execute(request)
      resultats = c.fetchall()
      for utilisateur in resultats:
         print(utilisateur)
Les n-uplets renvoyés obtiennent des valeurs converties en fonction des types de la base. Notamment si vous avez des booléens dans la base, ceux-ci seront transformés en valeurs 0 et 1 équivalents à False et True.

L'inconvénient de la méthode fetchall() est qu'elle va créer un buffer mémoire rempli avec l'ensemble des valeurs. Selon la taille de la base, cela peut poser des problèmes avec la gestion de cette mémoire. Il est alors possible d'utiliser une récupération de valeurs dans le flux de lecture par le biais de la méthode fetchone(), qui renverra la valeur None lorsqu'il n'y aura plus rien à récupérer de la base.

request = "select id, nom, score, date_inscription, actif from utilisateur"

   with db.cursor() as c:
      c.execute(request)
      while True:
         utilisateur = c.fetchone()
         if utilisateur is None:
               break
         print(utilisateur)

Il est parfois nécessaire de limiter le nombre de résultats renvoyés. Plutôt que de faire une boucle ave une condition de sortie, il vaut mieux définir cette limite dans la requête par l'intermdiaire d'une option du langage SQL limit.

select id, nom, score, date_inscription, actif from utilisateur limit 1

Vous pouvez également utiliser la méthode fetchmany() qui présente le meilleur des mondes entre fetchall() qui mange la mémoire et fetchone() qui pénalise les performances. Avec fetchmany(), vous pouvez préciser le nombre de résultats à renvoyer. S'il n'y a plus de résultats, la méthode retourne une liste vide.

request = "select id, nom, score, date_inscription, actif from utilisateur"

   with db.cursor() as c:
      c.execute(request)
      while True:
         resultats = c.fetchmany(10)
         if not resultats:
               break
         for utilisateur in resultats:
               print(utilisateur)
Dans l'exemple la méthode retourne 10 utilisateurs par la requête de sélection.

Conditions dans les requêtes

Les requêtes peuvent prendre des paramètres pour réduire les risques d'attaques et gagner en souplesse dans les appels. Les paramètres sont spécifiés par %s et prennent un n-uplet comme second paramètre de la méthode execute().

request = "select id, nom, score, date_inscription, actif from utilisateur where nom = %s"

params = ("david",)

   with db.cursor() as c:
      c.execute(request, params)
      resultats = c.fetchall()
      for utilisateur in resultats:
         print(utilisateur)

Insertion de données

Pour insérer une données il faut utiliser la requête SQL Insert en la passant à la méthode execute() du curseur.

with db.cursor() as c:
   c.execute("insert into utilisateur (nom, score, actif) values ('david', 10, TRUE)")
   db.commit()
En supposant que la table utilisateur dispose des champs non, score et actif, et qu'aucune erreur n'est faite dans la requête, la méthode commit() permet de valider les modifications. C'est obligatoire en fin de modification d'une base. Si cette commande n'est pas exécutée, aucune modification ne sera apportée à la base.

Il y a toutefois un problème dans la commande SQL précédente : elle n'est pas sécurisée. Il est recommandé de fournir les valeurs à la requête sous la forme de paramètres et non directement dans la requête.

request = """insert into utilisateur (nom, score, actif) values (%s, %s, %s)"""
params = ("david", 10, True)

   with db.cursor() as c:
      c.execute(request, params)
      db.commit()

De la même façon il existe la méthode executemany() pour l'insertion de multiples lignes en une seule fois.

request = """insert into utilisateur(nom, score, actif) values (%s, %s, %s)"""
params = [
   ("david", 10, True),
   ("laurence", 15, True),
   ("julien", 12, False)
]

   with db.cursor() as c:
      c.executemany(request, params)
      db.commit()
      print("Nombre de lignes insérées :", c.rowcount)
Pour connaître le nombre de lignes traitées, utilisez la méthode rowcount() du curseur.

Modification des données

Toutes les autres requêtes de modification des bases de données reposent sur le principe d'utilisation de la méthode execute() et de commit() en fin de requêtage. La méthode rowcount() permet de connaître le nombre de lignes impactées.