SPA – les bases de données

Projets

En 2022, on estime que 41 186 animaux ont été adoptés à la SPA et 44 199 animaux ont été recueillis par celle-ci. Afin de pouvoir répertorier les animaux présents à la SPA, une table de données est l’outil indispensable.

I – Présentation du projet

Pour commencer, la réalisation de la base de données se porte sur la simulation d’une SPA. Celle-ci se compose d’une page d’Acceuil comportant le menu en haut de la page.

Puis d’une page Ajouter où l’on rentre les informations sur un nouvel animal.

Par la suite, d’une page Modifier permettant de modifier les informations sur un animal déjà enregistré sur la base de données en rentrant son id et en choisissant la donnée à modifier. De plus, lorsque vous choisissez de supprimer un animal, il vous suffit de rentrer son id et de cliquer sur Supprimer l’animal ayant cet id.

Et enfin, la page Parcourir où l’on choisit par quel type de donnée nous souhaitons faire la recherche (id, espèce, race, nom, date et lieu) et où l’on écrit la valeur recherchée ou si c’est une date, si elle est égale, plus grande, plus petites, etc.

Pour chaque page, il est possible de supprimer toute la table, c’est-à-dire supprimer tout le tableau crée. Lorsque vous ajoutez et modifiez, le résultat de Parcourir se trouve sur la fenêtre blanche en dessous de Rechercher.

II – Mise en place du projet

Dans un premier temps, il a été primordial d’importer les librairies présentes pour la création de la base de données.

from tkinter import *
from tkinter import ttk
from tkinter.messagebox import showinfo
import sqlite3

La première ligne de code permet d’utiliser le nom des classes et fonctions définies sur tkinter. La seconde permet de créer des widgets. La troisième, showinfo permet de fournir des instructions à l’utilisateur. Enfin, d’importer le module SQLite3 permet d’interagir avec la base de données en .db .

Après avoir importé les modules dont on a besoin, il faut établir une connexion avec la base de données « base_SPA.db » et créer un curseur pour exécuter les commandes SQL .

connection = sqlite3.connect('base_SPA.db')
curseur = connection.cursor()
Ensuite, il faut créer les différentes fenêtres telles que accueil, ajouter, modifier, parcourir qui sont présents tout le long et dès le début à la page Accueil avec le bouton pour vider la table, c'est-à-dire effacer les données de la table.
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import showinfo
import sqlite3

#génération du lien de la base de donnée
connection = sqlite3.connect('base_SPA.db')
curseur = connection.cursor()

#génération de la base de donnée si elle n'existe pas
curseur.execute("CREATE TABLE IF NOT EXISTS ANNIMAL(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, nom TEXT, espèce TEXT, race TEXT, age INT, trouvé_où TEXT)")

connection.commit()
curseur.close()
connection.close()

# création de toutes les fenêtres
def afficher_nouvelle_fenetre(message):
    fenetre.withdraw()  # Masque la fenêtre actuelle
    nouvelle_fenetre = Toplevel(fenetre)
    nouvelle_fenetre.title("Nouvelle Fenêtre")
    nouvelle_fenetre.geometry("720x555") 
    Label(nouvelle_fenetre, text=message).pack(padx=20, pady=20)

def affiche_acceuil():
    cadre_pile.append(cadre_acceuil)  # création de la page d'accueil
    afficher_cadre(cadre_acceuil)

def affiche_ajoute():
    cadre_pile.append(cadre_ajoute)  # création de la page ajoute
    afficher_cadre(cadre_ajoute)

def affiche_modifier():
    cadre_pile.append(cadre_modifier)  # création de la page modifier
    afficher_cadre(cadre_modifier)
    
def affiche_parcourir():
    cadre_pile.append(cadre_parcourir)  # création de la page parcourir
    afficher_cadre(cadre_parcourir)


def afficher_cadre(cadre):
    for c in [cadre_acceuil, cadre_ajoute, cadre_modifier, cadre_parcourir]:
        c.pack_forget()
    cadre.pack()

#génération de la fenêtre
fenetre = Tk()

fenetre.title("SPA - les bases de données")
fenetre.geometry("720x555")
fenetre.config(bg="#C2C2C2")
fenetre.iconbitmap("logo.ico")

#fonction pour vider la table
def vider_table():
    connection = sqlite3.connect('base_SPA.db')
    curseur = connection.cursor()
    curseur.execute("DROP TABLE ANNIMAL")
    curseur.execute("CREATE TABLE ANNIMAL(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, nom TEXT, espèce TEXT, race TEXT, age INT, trouvé_où TEXT)")
    connection.commit()
    curseur.close()
    connection.close()
    
bouton_vider_table = Button(fenetre, text="vider la table", font=("Consolas",15), bg="white", fg="black",command = vider_table)
bouton_vider_table.place(x=530,y=480)

# Cadres pour différentes pages
cadre_acceuil = Frame(fenetre, bg="#C2C2C2")
cadre_ajoute = Frame(fenetre, bg="#C2C2C2")
cadre_modifier = Frame(fenetre, bg="#C2C2C2")
cadre_parcourir = Frame(fenetre, bg="#C2C2C2")

cadre_acceuil.pack()

# Création du menu
menubar = Menu(fenetre)

# Ajout des commandes directement au menu principal
menubar.add_command(label="Acceuil", command=affiche_acceuil)
menubar.add_command(label="Ajouter", command=affiche_ajoute)
menubar.add_command(label="Modifier", command=affiche_modifier)
menubar.add_command(label="Parcourir", command=affiche_parcourir)

# Configuration de la fenêtre avec la barre de menus
fenetre.config(menu=menubar)

# Initialisation de la pile des cadres
cadre_pile = [cadre_acceuil]

fenetre.mainloop()

Les fonctions permettent de gérer la navigation entre les différentes pages en fonction des actions de l’utilisateur. De plus, elles permettent de masquer les cadres précédemment affichés et affichent le cadre correspondant à la page demandée.

Après avoir créé nos différentes pages, il faut les construire, rajouter du texte, du champ de texte, etc. Tout d’abord, commence la page d’accueil, très simplement, on crée des blocs :

# création des "blocs" 
titre_acceuil = Label(cadre_acceuil, text="Bienvenue sur la base de données de la SPA", font=("Consolas", 20), bg="#C2C2C2", fg="black")
soustitre_acceuil = Label(cadre_acceuil, text="DONNONS-LEUR AUTANT QU'ILS NOUS APPORTENT !", font=("Consolas", 13), bg="#C2C2C2", fg="black")

# affichage de ces blocs
titre_acceuil.pack(pady=20)
soustitre_acceuil.pack()

Après cela, il ne nous reste plus qu’à créer les autres pages.

# création des different blocs + affichage des blocs
titre_ajoute = Label(cadre_ajoute, text="AJOUTER", font=("Consolas", 20), bg="#C2C2C2", fg="black")
titre_ajoute.pack(pady=20)
soustitre_ajoute = Label(cadre_ajoute, text="Veuillez entrer les données de l'animal", font=("Consolas", 13), bg="#C2C2C2", fg="black")
soustitre_ajoute.pack()
desc_chmp_nom_str_ajoute = Label(cadre_ajoute, text="entrez son nom", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp_nom_str_ajoute.pack()
chmp_nom_str_ajoute = Entry(cadre_ajoute, font=("Helvetica",15), bg="#ffffff", fg="black", width=30)
chmp_nom_str_ajoute.pack()
desc_chmp_espece_str_ajoute = Label(cadre_ajoute, text="entrez son espèce", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp_espece_str_ajoute.pack()
chmp_espece_str_ajoute = Entry(cadre_ajoute, font=("Helvetica",15), bg="#ffffff", fg="black", width=30)
chmp_espece_str_ajoute.pack()
desc_chmp_race_str_ajoute = Label(cadre_ajoute, text="entrez sa race", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp_race_str_ajoute.pack()
chmp_race_str_ajoute = Entry(cadre_ajoute, font=("Helvetica",15), bg="#ffffff", fg="black", width=30)
chmp_race_str_ajoute.pack()
desc_chmp_age_str_ajoute = Label(cadre_ajoute, text="entrez son âge", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp_age_str_ajoute.pack()
chmp_age_str_ajoute = Entry(cadre_ajoute, font=("Helvetica",15), bg="#ffffff", fg="black", width=30)
chmp_age_str_ajoute.pack()
desc_chmp_localisation_str_ajoute = Label(cadre_ajoute, text="entrez le lieu où il a été trouvé", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp_localisation_str_ajoute.pack()
chmp_localisation_str_ajoute = Entry(cadre_ajoute, font=("Helvetica",15), bg="#ffffff", fg="black", width=30)
chmp_localisation_str_ajoute.pack()

#fonction pour ajouter les donnée choisies dans les champs de texte de la page ajouter dans la base de donnéee
def ajouter_donnee():
    connection = sqlite3.connect('base_SPA.db')
    curseur = connection.cursor()
    data = (chmp_nom_str_ajoute.get(),chmp_espece_str_ajoute.get(),chmp_race_str_ajoute.get(),chmp_age_str_ajoute.get(),chmp_localisation_str_ajoute.get())
    curseur.execute("INSERT INTO ANNIMAL (nom,espèce,race,age,trouvé_où) VALUES (?,?,?,?,?)",data)
    connection.commit()
    curseur.close()
    connection.close()

# création et placement du bouton utiliser pour valider l'ajout de donnée
bouton_ajouter = Button(cadre_ajoute, text="Ajouter l'annimal", font=("Consolas",15), bg="white", fg="black",command = ajouter_donnee)
bouton_ajouter.pack(pady=20)

Dans ce code, nous créons la fenêtre Ajouter avec les informations à remplir. Lorsque l’on clique sur le bouton Ajouter l’animal, celui ci sera ajouté automatiquement à la table de données.

# création des different blocs + affichage des blocs
titre_modifier = Label(cadre_modifier, text="MODIFIER", font=("Consolas", 20), bg="#C2C2C2", fg="black")
titre_modifier.pack(pady=20)
desc_chmp_modifier = Label(cadre_modifier, text="entrez l'id de l'annimal", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp_modifier.pack()
chmp_str_modifier = Entry(cadre_modifier, font=("Helvetica",15), bg="#ffffff", fg="black", width=5)
chmp_str_modifier.pack()

# création de la liste déroulante
desc_liste_deroul_modifier = Label(cadre_modifier, text="Choissisez quel donnée voulez vous modifier", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_liste_deroul_modifier.pack(pady=10)
liste_choix = ["Nom","Race","Espèce","Age","Localisation"]
liste_deroulante = ttk.Combobox(cadre_modifier, values=liste_choix)
liste_deroulante.pack()

desc_chmp2_modifier = Label(cadre_modifier, text="entrez la modification", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_chmp2_modifier.pack(pady=10)
chmp2_str_modifier = Entry(cadre_modifier, font=("Helvetica",15), bg="#ffffff", fg="black", width=30)
chmp2_str_modifier.pack()

# fonction pour modifier une donnée dans la base de donnée à partir de la liste déroulante et le champ de texte
def modifier_donnee():
    select = liste_deroulante.get()
    datas = (chmp2_str_modifier.get(),chmp_str_modifier.get())
    connection = sqlite3.connect('base_SPA.db')
    curseur = connection.cursor()
    if select == "Nom":
        curseur.execute("UPDATE ANNIMAL SET nom = ? WHERE id = ?",datas)
    if select == "Race":
        curseur.execute("UPDATE ANNIMAL SET race = ? WHERE id = ?",datas)
    if select == "Espèce":
        curseur.execute("UPDATE ANNIMAL SET espèce = ? WHERE id = ?",datas)
    if select == "Age":
        curseur.execute("UPDATE ANNIMAL SET age = ? WHERE id = ?",datas)
    if select == "Localisation":
        curseur.execute("UPDATE ANNIMAL SET trouvé_où = ? WHERE id = ?",datas)
    connection.commit()
    curseur.close()
    connection.close()

# fonction pour supprimer toutes les données lié à un identifiant dans la base de donnée   
def supprimer_donnee():
    sup_select = chmp_str_modifier.get()
    connection = sqlite3.connect('base_SPA.db')
    curseur = connection.cursor()
    curseur.execute("DELETE FROM ANNIMAL WHERE id = ?",sup_select)
    connection.commit()
    curseur.close()
    connection.close()

# création et placement des boutons pour valider les modifications / suppressions
bouton_sup = Button(cadre_modifier, text="Supprimer l'annimal ayant cet id", font=("Consolas",15), bg="white", fg="black", command = supprimer_donnee)
bouton_sup.pack(pady=30)
bouton_modifier = Button(cadre_modifier, text="Modifier", font=("Consolas",15), bg="white", fg="black", command = modifier_donnee)
bouton_modifier.pack()

La fenêtre modifier quant à elle a besoin de l‘id de l’animal. En effet, pour modifier une information sur un animal, la personne doit rentrer l’id présente sur la table de donnée correspondant à l’animal, après cela, elle choisit l‘information à modifier dans la liste déroulante puis rentre la correction à faire. Ensuite, cette fenêtre abrite aussi la possibilité de supprimer l’animal comme cela a été dit précédemment grâce à la fonction supprimer_donnee() par l’id de l’animal.

# création des different blocs + affichage des blocs
titre_parcourir = Label(cadre_parcourir, text="PARCOURIR", font=("Consolas", 20), bg="#C2C2C2", fg="black")
titre_parcourir.pack(pady=10)
desc_liste_deroulante_parcourir = Label(cadre_parcourir, text="Choississez par qu'elle type de donnee souhaitez vous rechercher", font=("Consolas", 13), bg="#C2C2C2", fg="black")
desc_liste_deroulante_parcourir.pack(pady=10)

# création de la liste déroulante du type de donnée
liste_deroulante_parcourir = ttk.Combobox(cadre_parcourir, values=["id","Nom","Espèce", "Age","Race","Localisation"])
liste_deroulante_parcourir.set("id")
liste_deroulante_parcourir.pack(pady=10)

# création du cadre blanc où apparaissent les recherches effectuées
frame_info_recherche = Frame(cadre_parcourir, bg="#C2C2C2",heigh = 50,width=650)
frame_info_recherche.pack_propagate(False) 
frame_info_recherche.pack()

desc_chmp_str_parcourir = Label(frame_info_recherche, text="écrivez cette information de recherche", font=("Consolas", 10), bg="#C2C2C2", fg="black")
desc_chmp_str_parcourir.place(x=0,y=0)

chmp_str_parcourir = Entry(frame_info_recherche, font=("Helvetica",10), bg="#ffffff", fg="black", width=15)
chmp_str_parcourir.place(x=0,y=23)

desc_chmp_str_parcourir = Label(frame_info_recherche, text="Si c'est une valeur elle doit être :", font=("Consolas", 10), bg="#C2C2C2", fg="black")
desc_chmp_str_parcourir.place(x=390,y=0)

# création de la liste déroulante pour préciser la recherche par valeurs numériques
liste_deroulante_info_recherche = ttk.Combobox(frame_info_recherche, values=["=","<=",">=","<",">"],width=15)
liste_deroulante_info_recherche.set("=")
liste_deroulante_info_recherche.place(x=390,y=23)

variable = StringVar()
variable.set("1")
chmp_str_info_recherche_parcourir = Entry(frame_info_recherche,textvariable=variable, font=("Helvetica",10), bg="#ffffff", fg="black", width=15)
chmp_str_info_recherche_parcourir.place(x=510,y=23)

# création de la variable qui stocke tout le résultat d'une recherche
global recherche
recherche = ""

# fonction pour construire notre variable
def parcourir_donnee():
    global recherche
    recherche = ""
    connection = sqlite3.connect('base_SPA.db')
    curseur = connection.cursor()
    data = [chmp_str_parcourir.get()]
    data2 = [chmp_str_info_recherche_parcourir.get()]
    if liste_deroulante_parcourir.get() == "Nom":
        recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE nom = ?",data).fetchall()
    if liste_deroulante_parcourir.get() == "Race":
        recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE race = ?",data).fetchall()
    if liste_deroulante_parcourir.get() == "Espèce":
        recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE espèce = ?",data).fetchall()
    if liste_deroulante_parcourir.get() == "Localisation":
        recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE trouvé_où = ?",data).fetchall()
    if liste_deroulante_parcourir.get() == "Age":
        if liste_deroulante_info_recherche.get() == "=":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE age = ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == "<":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE age < ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == ">":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE age > ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == "<=":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE age <= ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == ">=":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE age >= ?",data2).fetchall()
    if liste_deroulante_parcourir.get() == "id":
        if liste_deroulante_info_recherche.get() == "=":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE id = ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == "<":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE id < ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == ">":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE id > ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == "<=":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE id <= ?",data2).fetchall()
        elif liste_deroulante_info_recherche.get() == ">=":
            recherche = curseur.execute("SELECT nom,espèce,race,age,trouvé_où FROM ANNIMAL WHERE id >= ?",data2).fetchall()
    connection.commit()
    curseur.close()
    connection.close()

# fonction pour afficher la recherche sous une forme lisible
def texte_parcourir():
    texte_widget_frame_parcourir.delete("1.0","end")
    parcourir_donnee()
    for car in str(recherche):
        if car == "[" or car == "]" or car == "(" or car == "'"  :
            texte_widget_frame_parcourir.insert(INSERT,"")
        elif car == ",":
            texte_widget_frame_parcourir.insert(INSERT,"")
        elif car == ")":
            texte_widget_frame_parcourir.insert(INSERT,"\n")
        else :
            texte_widget_frame_parcourir.insert(INSERT,car)
  
# création et placement du bouton pour valider une recherche
bouton_parcourir = Button(cadre_parcourir, text="Rechercher", font=("Consolas",15), bg="white", fg="black",command = texte_parcourir)
bouton_parcourir.pack(pady=10)


frame_parcourir = Frame(cadre_parcourir, bg="#ffffff",heigh = 210,width=650)
frame_parcourir.pack_propagate(False) 
frame_parcourir.pack()

# création et placement de la barre de scroll lié à la recherche effectuée
scrollbar = Scrollbar(frame_parcourir, orient=VERTICAL)
scrollbar.pack(side=RIGHT, fill=Y)

texte_widget_frame_parcourir = Text(frame_parcourir, yscrollcommand=scrollbar.set)
texte_widget_frame_parcourir.pack(fill=BOTH, expand=True)

scrollbar = Scrollbar(texte_widget_frame_parcourir)

scrollbar.config(command=texte_widget_frame_parcourir.yview)

texte_recherche_parcourir = Text(frame_parcourir)

Dans ce code, nous créons la fenêtre Parcourir avec toutes ses informations.

Puis, finalement, on peut terminer le script :

# Affichage de la page d'accueil au lancement du script
cadre_acceuil.pack()

# Création du menu
menubar = Menu(fenetre)

# Ajout des commandes directement au menu principal
menubar.add_command(label="Acceuil", command=affiche_acceuil)
menubar.add_command(label="Ajouter", command=affiche_ajoute)
menubar.add_command(label="Modifier", command=affiche_modifier)
menubar.add_command(label="Parcourir", command=affiche_parcourir)

# Configuration de la fenêtre avec la barre de menus
fenetre.config(menu=menubar)

# Initialisation de la pile des cadres
cadre_pile = [cadre_acceuil]

fenetre.mainloop()

Cette fin de script permet d’afficher l’interface et ses informations. Sans cela, Le script ne serait pas utilisable

III – Conclusion

Ainsi, ce projet nous a permis de mobiliser nos bases acquises en python et SQL pour monter un projet traitant sur les bases de données. Ce type de projet n’est pas des plus simples compte tenu de la technique à avoir et des difficultés rencontrées telles que le positionnement des blocs et les interactions avec la base de données. Pour continuer, il est important dans ce type de projets de comprendre son code ligne à ligne afin de ne pas se tromper sur un nom, une valeur ou autres.