La construction de projets est sans doute l'un des moyens les plus accessibles et les plus efficaces d'apprendre à programmer. Les projets réels nécessitent que vous appliquiez des compétences de codage différentes et variées. Ils vous encouragent également à rechercher des sujets qui apparaissent lorsque vous résolvez des problèmes dans le processus de développement. Dans ce didacticiel, vous allez créer une application de carnet de contacts avec Python, PyQt et SQLite.
Dans ce didacticiel, vous apprendrez à :
- Créer une interface utilisateur graphique (GUI) pour votre application de carnet d'adresses utilisant Python et PyQt
- Connecter l'application à une base de données SQLite en utilisant le support SQL de PyQt
- Gérer les données de contact à l'aide de l'architecture Model-View de PyQt
À la fin de ce projet, vous disposerez d'une application de carnet de contacts fonctionnelle qui vous permettra de stocker et de gérer vos informations de contact.
Pour obtenir le code source complet de l'application ainsi que le code de chaque étape de ce didacticiel, cliquez sur le lien ci-dessous :
Obtenez le code source : Cliquez ici pour obtenir le code source que vous utiliserez pour créer un carnet de contacts avec Python, PyQt et SQLite dans ce didacticiel.
Démo :Un carnet de contacts avec Python
Les carnets de contacts sont un type d'application utile et largement utilisé. Ils sont partout. Vous avez probablement un carnet de contacts sur votre téléphone et sur votre ordinateur. Avec un carnet de contacts, vous pouvez stocker et gérer les informations de contact des membres de votre famille, de vos amis, de vos collègues, etc.
Dans ce didacticiel, vous allez coder une application d'interface graphique de carnet de contacts avec Python, SQLite et PyQt. Voici une démonstration de l'apparence et du fonctionnement de votre carnet d'adresses après avoir suivi les étapes de ce didacticiel :
Votre carnet de contacts fournira l'ensemble minimal de fonctionnalités requises pour ce type d'application. Vous pourrez afficher, créer, mettre à jour et supprimer les informations de votre liste de contacts.
Aperçu du projet
Pour créer votre application de carnet d'adresses, vous devez organiser le code en modules et packages et donner à votre projet une structure cohérente. Dans ce didacticiel, vous utiliserez la structure de répertoires et de fichiers suivante :
rpcontacts_project/
│
├── rpcontacts/
│ ├── __init__.py
│ ├── views.py
│ ├── database.py
│ ├── main.py
│ └── model.py
│
├── requirements.txt
├── README.md
└── rpcontacts.py
Voici un bref résumé du contenu de votre répertoire de projet :
rpcontacts_project/
est le répertoire racine du projet. Il contiendra les fichiers suivants :requirements.txt
fournit la liste des exigences du projet.README.md
fournit des informations générales sur le projet.rpcontacts.py
fournit le script de point d'entrée pour exécuter l'application.
rpcontacts/
est un sous-répertoire qui fournit le package principal de l'application. Il fournit les modules suivants :__init__.py
views.py
database.py
main.py
model.py
Vous couvrirez chacun de ces fichiers étape par étape dans ce didacticiel. Le nom de chaque fichier donne une idée de son rôle dans l'application. Par exemple, views.py
contiendra le code pour générer l'interface graphique des fenêtres et des boîtes de dialogue, database.py
contiendra le code pour travailler avec la base de données, et main.py
hébergera l'application elle-même. Enfin, model.py
implémentera le modèle pour gérer les données dans la base de données de l'application.
En général, l'application aura une fenêtre principale pour afficher, ajouter, supprimer et mettre à jour les contacts. Il aura également une boîte de dialogue pour ajouter de nouveaux contacts à la base de données.
Prérequis
Pour tirer le meilleur parti de ce projet, une connaissance préalable de la programmation graphique avec Python et PyQt serait utile. À cet égard, vous devrez connaître les bases pour :
- Créer des applications graphiques avec PyQt et Python
- Créer et mettre en page des interfaces graphiques avec PyQt
- Gérer les bases de données SQL avec Python et PyQt
- Travailler avec des bases de données SQLite
Pour approfondir ces sujets, vous pouvez consulter les ressources suivantes :
- Python et PyQt :création d'une calculatrice de bureau à interface graphique
- Python et PyQt :création de menus, de barres d'outils et de barres d'état
- Mise en page PyQt :créez des applications graphiques d'aspect professionnel
- Gestion des bases de données SQL avec PyQt :les bases
- Introduction aux bibliothèques SQL Python
- Gestion des données avec Python, SQLite et SQLAlchemy
Ne vous inquiétez pas si vous n'êtes pas un expert dans ces domaines avant de commencer ce didacticiel. Vous apprendrez à travers le processus de vous salir les mains sur un vrai projet. Si vous êtes bloqué, prenez votre temps et consultez les ressources liées ci-dessus. Revenez ensuite au code.
L'application de carnet de contacts que vous allez créer dans ce didacticiel a une seule dépendance externe :PyQt.
Remarque : Dans ce didacticiel, vous utiliserez PyQt version 5.15.2 pour créer votre application de carnet de contacts. La version 5.15.2 est requise pour que le projet fonctionne sur macOS Big Sur.
La version 6.0 de PyQt est sortie le 4 janvier 2021. Il s'agit de la première version de la bibliothèque qui se lie à la version 6 de Qt. Cependant, le projet de ce didacticiel n'a pas été testé avec PyQt 6.0.
Si vous ressentez le besoin d'exécuter le projet avec cette nouvelle version de PyQt, essayez-le. Comme indice, vous devriez pip install PyQt6
puis mettez à jour les importations pour utiliser PyQt6
au lieu de PyQt5
.
Pour suivre les meilleures pratiques dans votre processus de développement, vous pouvez commencer par créer un environnement virtuel, puis installer PyQt en utilisant pip
. Une fois que vous avez installé PyQt, vous êtes prêt à commencer à coder !
Étape 1 :Créer l'application squelette du carnet de contacts avec PyQt
Dans cette première étape, vous allez créer une application graphique PyQt minimale mais fonctionnelle pour fournir la base sur laquelle vous commencerez à créer le carnet de contacts. Vous créerez également la structure de projet minimale requise, y compris le package principal du projet et un script de point d'entrée pour exécuter l'application.
Tout le code et les fichiers que vous ajouterez au projet de carnet de contacts dans cette section sont collectés sous le source_code_step_1/
annuaire. Vous pouvez les télécharger en cliquant sur le lien ci-dessous :
Obtenez le code source : Cliquez ici pour obtenir le code source que vous utiliserez pour créer un carnet de contacts avec Python, PyQt et SQLite dans ce didacticiel.
À la fin de cette section, vous serez en mesure d'exécuter l'application squelette de l'interface graphique pour votre carnet de contacts pour la première fois.
Structurer le projet de carnet d'adresses
Pour commencer à coder l'application, allez-y et créez un nouveau répertoire appelé rpcontacts_project/
. Ce sera le répertoire racine du projet. Créez maintenant un nouveau sous-répertoire appelé rpcontacts/
dans rpcontacts_project/
. Ce sous-répertoire contiendra le package principal de l'application. Enfin, lancez votre éditeur de code ou IDE dans le répertoire racine.
Pour transformer un répertoire en package, Python a besoin d'un __init__.py
module pour initialiser le package. Créez ce fichier dans rpcontacts/
et ajoutez-y le code suivant :
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
Ce fichier indique à Python que rpcontacts
est un paquet. Le code du fichier s'exécute lorsque vous importez le package ou certains de ses modules.
Vous n'avez pas besoin de mettre de code dans un __init__.py
fichier pour initialiser le package. Un __init__.py
vide le fichier fera le travail. Cependant, dans ce cas, vous définissez une constante au niveau du module appelée __version__
pour contenir le numéro de version de votre application.
Création de la fenêtre principale de l'application
Il est maintenant temps de créer la fenêtre principale de votre carnet de contacts. Pour ce faire, créez un module appelé views.py
dans vos rpcontacts
emballer. Ajoutez ensuite le code suivant au module et enregistrez-le :
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtWidgets import (
QHBoxLayout,
QMainWindow,
QWidget,
)
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("RP Contacts")
self.resize(550, 250)
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.layout = QHBoxLayout()
self.centralWidget.setLayout(self.layout)
Tout d'abord, vous importez les classes requises depuis PyQt5.QtWidgets
. Ensuite, vous créez Window
. Cette classe hérite de QMainWindow
et fournit le code pour générer la fenêtre principale de l'application. Dans la méthode d'initialisation, vous définissez le titre de la fenêtre sur "RP Contacts"
, redimensionnez la fenêtre à 550
par 250
pixels, définissez et configurez le widget central à l'aide de QWidget
, et enfin définir une disposition pour le widget central à l'aide d'une disposition de boîte horizontale.
Codage et exécution de l'application
Puisque vous avez déjà une fenêtre principale pour le carnet de contacts, il est temps d'écrire le code pour créer une application PyQt fonctionnelle en utilisant QApplication
. Pour ce faire, créez un nouveau module appelé main.py
dans vos rpcontacts
package et ajoutez-y le code suivant :
# -*- coding: utf-8 -*-
# rpcontacts/main.py
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Create the main window
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec())
Dans ce module, vous importez sys
pour accéder à exit()
, qui permet de quitter proprement l'application lorsque l'utilisateur ferme la fenêtre principale. Ensuite, vous importez QApplication
de PyQt5.QtWidgets
et Window
à partir de views
. La dernière étape consiste à définir main()
comme fonction principale de votre application.
À l'intérieur de main()
, vous instanciez QApplication
et Window
. Ensuite, vous appelez .show()
sur Window
, et enfin vous exécutez la boucle principale de l'application , ou boucle d'événements , en utilisant .exec()
.
Passez maintenant au répertoire racine du projet rpcontacts_project/
et créez un fichier nommé rpcontacts.py
. Ce fichier fournit le script de point d'entrée pour exécuter l'application. Ajoutez le code suivant au fichier et enregistrez-le :
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# rpcontacts_project/rpcontacts.py
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__":
main()
Ce fichier importe main()
depuis votre main.py
module. Ensuite, vous implémentez l'instruction conditionnelle traditionnelle qui appelle main()
si l'utilisateur exécute ce module en tant que script Python. Lancez maintenant l'application en exécutant la commande python rpcontacts.py
dans votre environnement Python. Vous obtiendrez la fenêtre suivante sur votre écran :
C'est ça! Vous avez créé une application graphique PyQt minimale mais fonctionnelle que vous pouvez utiliser comme point de départ pour créer votre carnet de contacts. À ce stade, votre projet devrait avoir la structure suivante :
./rpcontacts_project/
│
├── rpcontacts/
│ ├── __init__.py
│ ├── views.py
│ └── main.py
│
└── rpcontacts.py
Dans cette section, vous avez créé la structure minimale requise pour votre projet de carnet de contacts à l'aide de modules et de packages Python. Vous avez construit la fenêtre principale de l'application et assemblé le code passe-partout pour créer une application graphique PyQt. Vous avez également exécuté l'application pour la première fois. Ensuite, vous commencerez à ajouter des fonctionnalités à votre interface graphique.
Étape 2 :Créer l'interface graphique du carnet d'adresses avec Python
Maintenant que vous avez construit le squelette de votre application de carnet de contacts, vous pouvez commencer à coder l'interface graphique de la fenêtre principale. À la fin de cette section, vous aurez terminé les étapes requises pour créer l'interface graphique de votre carnet de contacts à l'aide de Python et PyQt. L'interface graphique ressemblera à ceci :
Au centre de la fenêtre, vous avez une vue tableau pour afficher votre liste de contacts. A droite du formulaire, vous avez trois boutons :
- Ajouter pour ajouter un nouveau contact à la liste
- Supprimer pour supprimer un contact sélectionné de la liste
- Tout effacer pour supprimer tous les contacts de la liste
Tout le code et les fichiers que vous ajouterez ou modifierez dans cette section sont collectés sous le source_code_step_2/
annuaire. Vous pouvez les télécharger en cliquant sur le lien ci-dessous :
Obtenez le code source : Cliquez ici pour obtenir le code source que vous utiliserez pour créer un carnet de contacts avec Python, PyQt et SQLite dans ce didacticiel.
Revenez à views.py
module et mettre à jour le code de Window
pour générer l'interface graphique ci-dessus :
1# -*- coding: utf-8 -*-
2# rpcontacts/views.py
3
4"""This module provides views to manage the contacts table."""
5
6from PyQt5.QtWidgets import (
7 QAbstractItemView,
8 QHBoxLayout,
9 QMainWindow,
10 QPushButton,
11 QTableView,
12 QVBoxLayout,
13 QWidget,
14)
15
16class Window(QMainWindow):
17 """Main Window."""
18 def __init__(self, parent=None):
19 """Initializer."""
20 # Snip...
21
22 self.setupUI()
23
24 def setupUI(self):
25 """Setup the main window's GUI."""
26 # Create the table view widget
27 self.table = QTableView()
28 self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
29 self.table.resizeColumnsToContents()
30 # Create buttons
31 self.addButton = QPushButton("Add...")
32 self.deleteButton = QPushButton("Delete")
33 self.clearAllButton = QPushButton("Clear All")
34 # Lay out the GUI
35 layout = QVBoxLayout()
36 layout.addWidget(self.addButton)
37 layout.addWidget(self.deleteButton)
38 layout.addStretch()
39 layout.addWidget(self.clearAllButton)
40 self.layout.addWidget(self.table)
41 self.layout.addLayout(layout)
Vous importez d'abord des classes PyQt supplémentaires à utiliser dans l'interface graphique. Voici quelques-unes des plus pertinentes :
QPushButton
pour créer l'Ajout , Supprimer , et Tout effacer boutonsQTableView
pour fournir la vue sous forme de tableau qui affiche la liste des contactsQAbstractItemView
pour fournir l'accès à la politique de comportement de sélection de vue de tableau
Dans ce code, le premier ajout à Window
est un appel à .setupUI()
à la fin de __init__()
. Cet appel génère l'interface graphique de la fenêtre principale lorsque vous exécutez l'application.
Voici ce que contient le code .setupUI()
fait :
- Ligne 27 crée un
QTableView
instance pour afficher la liste des contacts. - Ligne 28 définit le
.selectionBehavior
propriété àQAbstractItemView.SelectRows
. Cela garantit que lorsqu'un utilisateur clique sur n'importe quelle cellule de la vue du tableau, la ligne complète sera sélectionnée. Les lignes de la vue tableau contiennent toutes les informations relatives à un seul contact dans la liste des contacts. - Lignes 31 à 33 ajoutez les trois boutons à l'interface graphique :Ajouter , Supprimer , et Tout effacer . Ces boutons n'exécutent aucune action pour le moment.
- Lignes 35 à 41 créer et définir une mise en page cohérente pour tous les widgets de l'interface graphique.
Avec ces ajouts à Window
, vous pouvez relancer l'application. La fenêtre sur votre écran ressemblera à la fenêtre que vous avez vue au début de la section.
Remarque : Les numéros de ligne dans le code ci-dessus et dans le reste des exemples de code de ce didacticiel sont destinés à faciliter l'explication. Ils ne correspondent pas à l'ordre des lignes dans le module ou le script final.
Dans cette section, vous avez exécuté toutes les étapes nécessaires pour créer l'interface graphique de la fenêtre principale de votre carnet de contacts. Vous êtes maintenant prêt à commencer à travailler sur la façon dont votre application gérera et stockera vos données de contact.
Étape 3 :Configurer la base de données du carnet de contacts
À ce stade, vous avez créé une application PyQt et l'interface graphique de sa fenêtre principale pour créer votre projet de carnet de contacts. Dans cette section, vous allez écrire du code pour définir comment l'application se connecte à la base de données de contacts. Pour terminer cette étape, vous utiliserez SQLite pour gérer la base de données et le support SQL de PyQt pour connecter l'application à la base de données et travailler avec vos données de contact.
Le code source et les fichiers que vous ajouterez ou modifierez dans cette section sont stockés sous le source_code_step_3/
annuaire. Vous pouvez les télécharger en cliquant sur le lien ci-dessous :
Obtenez le code source : Cliquez ici pour obtenir le code source que vous utiliserez pour créer un carnet de contacts avec Python, PyQt et SQLite dans ce didacticiel.
Tout d'abord, revenez à main.py
dans le rpcontacts/
répertoire et mettre à jour le code pour créer la connexion à la base de données :
# -*- coding: utf-8 -*-
# rpcontacts/main.py
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main():
"""RP Contacts main function."""
# Create the application
app = QApplication(sys.argv)
# Connect to the database before creating any window
if not createConnection("contacts.sqlite"):
sys.exit(1)
# Create the main window if the connection succeeded
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())
Dans ce cas, vous importez d'abord createConnection()
de database.py
. Cette fonction contiendra du code pour créer et ouvrir une connexion à la base de données de contacts. Vous allez créer database.py
et écrivez createConnection()
dans la section suivante.
À l'intérieur de main()
, la première ligne en surbrillance est une tentative de création d'une connexion à la base de données à l'aide de createConnection()
. Si pour une raison quelconque l'application n'est pas capable de créer une connexion, alors l'appel à sys.exit(1)
fermera l'application sans créer d'élément graphique et indiquera qu'une erreur s'est produite.
Vous devez gérer la connexion de cette façon car l'application dépend de la base de données pour fonctionner correctement. Si vous n'avez pas de connexion fonctionnelle, votre application ne fonctionnera pas du tout.
Cette pratique permet de gérer les erreurs et de fermer proprement l'application en cas de problème. Vous pourrez également présenter à l'utilisateur des informations pertinentes sur l'erreur rencontrée par l'application lors de la tentative de connexion à la base de données.
Avec ces ajouts en place, il est temps de plonger dans le code de createConnection()
.
Connexion à la base de données avec PyQt et SQLite
La connexion de votre application de carnet de contacts à sa base de données associée est une étape fondamentale dans le développement de l'application. Pour ce faire, vous allez coder une fonction appelée createConnection()
, qui créera et ouvrira une connexion à la base de données. Si la connexion réussit, la fonction renverra True
. Sinon, il fournira des informations sur la cause de l'échec de la connexion.
Revenir au rpcontacts/
répertoire et créez un nouveau module appelé database.py
à l'intérieur. Ajoutez ensuite le code suivant à ce module :
1# -*- coding: utf-8 -*-
2# rpcontacts/database.py
3
4"""This module provides a database connection."""
5
6from PyQt5.QtWidgets import QMessageBox
7from PyQt5.QtSql import QSqlDatabase
8
9def createConnection(databaseName):
10 """Create and open a database connection."""
11 connection = QSqlDatabase.addDatabase("QSQLITE")
12 connection.setDatabaseName(databaseName)
13
14 if not connection.open():
15 QMessageBox.warning(
16 None,
17 "RP Contact",
18 f"Database Error: {connection.lastError().text()}",
19 )
20 return False
21
22 return True
Ici, vous importez d'abord certaines classes PyQt requises. Ensuite, vous définissez createConnection()
. Cette fonction prend un argument :databaseName
contient le nom ou le chemin d'accès au fichier de base de données SQLite physique dans votre système de fichiers.
Voici ce que contient le code createConnection()
fait :
- Ligne 11 crée la connexion à la base de données en utilisant
QSQLITE
chauffeur. - Ligne 12 définit le nom de fichier ou le chemin d'accès à la base de données.
- Ligne 14 tente d'ouvrir la connexion. Si un problème survient lors de l'appel à
.open()
, puis leif
le bloc de code affiche un message d'erreur puis renvoieFalse
pour indiquer que la tentative de connexion a échoué. - Ligne 22 renvoie
True
si la tentative de connexion réussit.
Vous avez déjà codé createConnection()
. Vous pouvez maintenant écrire le code pour créer les contacts
tables dans la base de données.
Création des contacts
Tableau
Avec la fonction qui crée et ouvre la connexion à la base de données en place, vous pouvez procéder au codage d'une fonction d'assistance pour créer les contacts
table. Vous utiliserez cette table pour stocker les informations sur vos contacts.
Voici le code qui implémente _createContactsTable()
:
# -*- coding: utf-8 -*-
# rpcontacts/database.py
# Snip...
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
def _createContactsTable():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery()
return createTableQuery.exec(
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection(databaseName):
# Snip...
_createContactsTable()
return True
Ici, vous ajoutez d'abord une nouvelle importation. Vous importez QSqlQuery
pour exécuter et manipuler des instructions SQL.
À l'intérieur de _createContactsTable()
, vous créez une QSqlQuery
exemple. Ensuite, vous appelez .exec()
sur l'objet de requête avec un CREATE TABLE
SQL basé sur une chaîne énoncé comme argument. Cette instruction crée une nouvelle table appelée contacts
dans votre base de données. Le tableau comporte les colonnes suivantes :
Colonne | Contenu |
---|---|
id | Un entier avec la clé primaire de la table |
name | Une chaîne avec le nom d'un contact |
job | Une chaîne avec le titre du poste d'un contact |
email | Une chaîne avec l'e-mail d'un contact |
Les contacts
table dans votre base de données stockera des informations pertinentes sur vos contacts.
La dernière étape pour finir de coder database.py
est d'ajouter un appel à _createContactsTable()
depuis l'intérieur de createConnection()
, juste avant le dernier return
déclaration. Cela garantit que l'application crée les contacts
table avant d'effectuer des opérations sur la base de données.
Une fois que vous avez créé les contacts
table, vous pouvez exécuter des tests sur la base de données et également ajouter des exemples de données pour des tests supplémentaires.
Tester la base de données du carnet de contacts
Jusqu'à présent, vous avez fini d'écrire le code requis pour gérer la connexion à la base de données du carnet de contacts. Dans cette section, vous effectuerez des tests pour vous assurer que ce code et la base de données elle-même fonctionnent correctement. Vous ajouterez également des exemples de données à la base de données pour effectuer des tests supplémentaires ultérieurement dans ce didacticiel.
Ouvrez maintenant un terminal ou une ligne de commande et accédez au répertoire racine du projet, rpcontacts_project/
. Une fois là-bas, lancez une session interactive Python et saisissez le code suivant :
>>> from rpcontacts.database import createConnection
>>> # Create a connection
>>> createConnection("contacts.sqlite")
True
>>> # Confirm that contacts table exists
>>> from PyQt5.QtSql import QSqlDatabase
>>> db = QSqlDatabase.database()
>>> db.tables()
['contacts', 'sqlite_sequence']
Ici, vous importez d'abord createConnection()
à partir de database.py
module. Ensuite, vous appelez cette fonction pour créer et ouvrir une connexion à la base de données de contacts. Le nom du fichier de la base de données est contacts.sqlite
. Comme ce fichier n'existe pas dans le répertoire racine du projet, SQLite le crée pour vous. Vous pouvez vérifier cela en jetant un coup d'œil à votre répertoire actuel.
Ensuite, vous confirmez que la base de données contient une table appelée contacts
. Pour ce faire, vous appelez .database()
sur QSqlDatabase
. Cette méthode de classe renvoie un pointeur vers la connexion actuelle à la base de données. Avec cette référence à la connexion, vous pouvez appeler .tables()
pour obtenir la liste des tables de la base de données. Notez que le premier tableau de la liste est contacts
, alors maintenant vous êtes sûr que tout fonctionne bien.
Vous pouvez maintenant préparer une requête SQL pour insérer des exemples de données dans les contacts
tableau :
>>> # Prepare a query to insert sample data
>>> from PyQt5.QtSql import QSqlQuery
>>> insertDataQuery = QSqlQuery()
>>> insertDataQuery.prepare(
... """
... INSERT INTO contacts (
... name,
... job,
... email
... )
... VALUES (?, ?, ?)
... """
... )
True
La requête ci-dessus vous permet d'insérer des valeurs spécifiques dans le name
, job
, et email
attributs et pour enregistrer ces valeurs dans la base de données. Voici un exemple de la façon de procéder :
>>> # Sample data
>>> data = [
... ("Linda", "Technical Lead", "[email protected]"),
... ("Joe", "Senior Web Developer", "[email protected]"),
... ("Lara", "Project Manager", "[email protected]"),
... ("David", "Data Analyst", "[email protected]"),
... ("Jane", "Senior Python Developer", "[email protected]"),
... ]
>>> # Insert sample data
>>> for name, job, email in data:
... insertDataQuery.addBindValue(name)
... insertDataQuery.addBindValue(job)
... insertDataQuery.addBindValue(email)
... insertDataQuery.exec()
...
True
True
True
True
True
Dans ce morceau de code, vous définissez d'abord data
pour conserver les coordonnées d'une liste de personnes. Ensuite, vous utilisez un for
boucle pour insérer les données en appelant .addBindValue()
. Ensuite, vous appelez .exec()
sur l'objet de requête pour exécuter efficacement la requête SQL sur la base de données.
Depuis tous les appels à .exec()
renvoie True
, vous pouvez conclure que les données ont été correctement insérées dans la base de données. Si vous souhaitez le confirmer, exécutez le code suivant :
>>> query = QSqlQuery()
>>> query.exec("SELECT name, job, email FROM contacts")
True
>>> while query.next():
... print(query.value(0), query.value(1), query.value(2))
...
Linda Technical Lead [email protected]
Joe Senior Web Developer [email protected]
Lara Project Manager [email protected]
David Data Analyst [email protected]
Jane Senior Python Developer [email protected]
C'est ça! Votre base de données fonctionne bien ! Vous avez maintenant quelques exemples de données pour tester l'application, et vous pouvez vous concentrer sur la façon de charger et d'afficher les informations de contact dans la fenêtre principale de votre carnet de contacts.
Étape 4 :Afficher et mettre à jour les contacts existants
Pour afficher vos données de contact dans la fenêtre principale de l'application, vous pouvez utiliser QTableView
. Cette classe fait partie de l'architecture Model-View de PyQt et fournit un moyen robuste et efficace d'afficher des éléments à partir d'un objet de modèle PyQt.
Les fichiers et le code que vous allez ajouter ou modifier dans cette section sont stockés sous le source_code_step_4/
annuaire. Pour les télécharger, cliquez sur le lien ci-dessous :
Obtenez le code source : Cliquez ici pour obtenir le code source que vous utiliserez pour créer un carnet de contacts avec Python, PyQt et SQLite dans ce didacticiel.
Une fois cette étape terminée, votre carnet de contacts ressemblera à ceci :
L'objet de vue de tableau dans la fenêtre principale fournit la fonctionnalité requise pour vous permettre de modifier et de mettre à jour rapidement les informations de contact.
Par exemple, pour mettre à jour le nom d'un contact, vous pouvez double-cliquer sur la cellule contenant le nom, mettre à jour le nom, puis appuyer sur Entrée pour enregistrer automatiquement les modifications dans la base de données. Mais avant de pouvoir le faire, vous devez créer un modèle et le connecter à la vue du tableau.
Création d'un modèle pour gérer les données de contact
PyQt fournit un riche ensemble de classes pour travailler avec des bases de données SQL. Pour votre application de carnet de contacts, vous utiliserez QSqlTableModel
, qui fournit un modèle de données modifiable pour une seule table de base de données. C'est parfait pour le travail puisque votre base de données a une seule table, contacts
.
Revenez à votre éditeur de code et créez un nouveau module appelé model.py
à l'intérieur du rpcontacts/
annuaire. Ajoutez le code suivant au fichier et enregistrez-le :
1# -*- coding: utf-8 -*-
2# rpcontacts/model.py
3
4"""This module provides a model to manage the contacts table."""
5
6from PyQt5.QtCore import Qt
7from PyQt5.QtSql import QSqlTableModel
8
9class ContactsModel:
10 def __init__(self):
11 self.model = self._createModel()
12
13 @staticmethod
14 def _createModel():
15 """Create and set up the model."""
16 tableModel = QSqlTableModel()
17 tableModel.setTable("contacts")
18 tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)
19 tableModel.select()
20 headers = ("ID", "Name", "Job", "Email")
21 for columnIndex, header in enumerate(headers):
22 tableModel.setHeaderData(columnIndex, Qt.Horizontal, header)
23 return tableModel
Dans ce code, vous effectuez d'abord certaines importations requises, puis vous créez ContactsModel
. Dans l'initialiseur de classe, vous définissez un attribut d'instance appelé .model
pour contenir le modèle de données.
Next, you add a static method to create and set up the model object. Here’s what the code in ._createModel()
does:
- Line 16 creates an instance of
QSqlTableModel()
calledtableModel
. - Line 17 associates the model object with the
contacts
table in your database. - Line 18 sets the
.editStrategy
property of the model toQSqlTableModel.OnFieldChange
. With this, you ensure that the changes on the model get saved into the database immediately. - Line 19 loads the table into the model by calling
.select()
. - Lines 20 to 22 define and set user-friendly headers for the
contacts
table’s columns. - Line 23 returns the newly created model.
At this point, you have your data model ready to use. Now you need to connect the table view widget to the model so you can present your users with the contact information.
Connecting the Model to the View
To display contact data in your contact book’s main window, you need to connect the table view with the data model. To perform this connection, you need to call .setModel()
on the table view object and pass the model as an argument:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
from .model import ContactsModel
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
# Snip...
self.contactsModel = ContactsModel()
self.setupUI()
def setupUI(self):
"""Setup the main window's GUI."""
# Create the table view widget
self.table = QTableView()
self.table.setModel(self.contactsModel.model)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
# Snip...
In this code, you first import ContactsModel
from model.py
. This class provides the model that manages the data in your contact database.
In the initializer of Window
, you create an instance of ContactsModel
. Then inside .setupUI()
, you call .setModel()
on .table
to connect the model with the table view. If you run the application after this update, then you’ll get the window you saw at the beginning of step 4.
Displaying and Updating Contacts
PyQt’s Model-View architecture provides a robust and user-friendly way to create GUI applications that manage databases. Models communicate with and access the data in the database. Any change in a model updates the database immediately. Views are responsible for displaying the data to the user and also for providing editable widgets to allow the user to modify the data directly in the view.
If the user modifies the data through the view, then the view internally communicates with and updates the model, which saves the changes to the physical database:
In this example, you double-click Joe’s Job domaine. This gives you access to an editable widget that allows you to modify the value in the cell. Then you update the job description from Senior Web Developer
to Web Developer
. When you hit Enter , the table view communicates the change to the model, and the model saves the change to the database immediately.
To confirm that the changes were successfully saved into the database, you can close the application and run it again. The table view should reflect your updates.
Step 5:Creating New Contacts
At this step, your contact book application provides functionality to load, display, and update the information about your contacts. Even though you’re able to modify and update the contact information, you can neither add nor remove contacts from the list.
All the files and the code you’ll add or modify in this section are collected in the source_code_step_5/
annuaire. To download them, click the link below:
Get the Source Code: Click here to get the source code you’ll use to build a contact book with Python, PyQt, and SQLite in this tutorial.
In this section, you’ll provide the required functionality to add new contacts to the database, using a pop-up dialog to enter the new information. The first step is to create the Add Contact dialog.
Creating the Add Contact Dialog
Dialogs are small windows that you can use to communicate with your users. In this section, you’ll code the contact book’s Add Contact dialog to allow your users add new contacts to their current list of contacts.
To code the Add Contact dialog, you’ll subclass QDialog
. This class provides a blueprint to build dialogs for your GUI applications.
Now open the views.py
module and update the import section like this:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QAbstractItemView,
QDialog,
QDialogButtonBox,
QFormLayout,
QHBoxLayout,
QLineEdit,
QMainWindow,
QMessageBox,
QPushButton,
QTableView,
QVBoxLayout,
QWidget,
)
The highlighted lines in the above code import the required classes to build the Add Contact dialog. With these classes in your namespace, add the following class at the end of views.py
:
1# -*- coding: utf-8 -*-
2# rpcontacts/views.py
3
4# Snip...
5class AddDialog(QDialog):
6 """Add Contact dialog."""
7 def __init__(self, parent=None):
8 """Initializer."""
9 super().__init__(parent=parent)
10 self.setWindowTitle("Add Contact")
11 self.layout = QVBoxLayout()
12 self.setLayout(self.layout)
13 self.data = None
14
15 self.setupUI()
16
17 def setupUI(self):
18 """Setup the Add Contact dialog's GUI."""
19 # Create line edits for data fields
20 self.nameField = QLineEdit()
21 self.nameField.setObjectName("Name")
22 self.jobField = QLineEdit()
23 self.jobField.setObjectName("Job")
24 self.emailField = QLineEdit()
25 self.emailField.setObjectName("Email")
26 # Lay out the data fields
27 layout = QFormLayout()
28 layout.addRow("Name:", self.nameField)
29 layout.addRow("Job:", self.jobField)
30 layout.addRow("Email:", self.emailField)
31 self.layout.addLayout(layout)
32 # Add standard buttons to the dialog and connect them
33 self.buttonsBox = QDialogButtonBox(self)
34 self.buttonsBox.setOrientation(Qt.Horizontal)
35 self.buttonsBox.setStandardButtons(
36 QDialogButtonBox.Ok | QDialogButtonBox.Cancel
37 )
38 self.buttonsBox.accepted.connect(self.accept)
39 self.buttonsBox.rejected.connect(self.reject)
40 self.layout.addWidget(self.buttonsBox)
There are a lot of things happening in this code. Here’s a summary:
- Line 5 defines a new class that inherits from
QDialog
. - Lines 7 to 15 define the class initializer. In this case, the most relevant addition is
.data
, which is an instance attribute that you’ll use to hold the data your users provide.
In .setupUI()
, you define the dialog’s GUI:
- Lines 20 to 25 add three
QLineEdit
objects:name
,job
, andemail
. You’ll use these line edits to take the user’s input for the name, job description, and email of the contact to add. They represent the corresponding fields in the database. - Lines 27 to 30 create a
QFormLayout
instance that arranges the line edits in a form. This layout manager also provides user-friendly labels for each line edit or field. - Lines 33 to 37 add a
QDialogButtonBox
object that provides two standard buttons:OK and Cancel . The OK button accepts the user’s input and the Cancel button rejects it. - Lines 38 and 39 connect the dialog’s built-in
.accepted()
and.rejected()
signals with the.accept()
andreject()
slots, respectively. In this case, you’ll rely on the dialog’s built-in.reject()
slot, which closes the dialog without processing the input. Other than that, you just need to code the.accept()
slot.
To code the dialog’s .accept()
slot, you need to consider that any user input needs validation to make sure that it’s correct and safe. This is especially true when you’re working with SQL databases because of the risk of an SQL injection attack.
In this example, you’ll add a minimal validation rule just to make sure that the user provides data for each input field in the dialog. However, adding your own, more robust validation rules would be a good exercise.
Without further ado, get back to AddDialog
and add the following code for its .accept()
slot:
1# -*- coding: utf-8 -*-
2# rpcontacts/views.py
3
4# Snip...
5class AddDialog(QDialog):
6 def __init__(self, parent=None):
7 # Snip...
8
9 def setupUI(self):
10 # Snip...
11
12 def accept(self):
13 """Accept the data provided through the dialog."""
14 self.data = []
15 for field in (self.nameField, self.jobField, self.emailField):
16 if not field.text():
17 QMessageBox.critical(
18 self,
19 "Error!",
20 f"You must provide a contact's {field.objectName()}",
21 )
22 self.data = None # Reset .data
23 return
24
25 self.data.append(field.text())
26
27 if not self.data:
28 return
29
30 super().accept()
The code within .accept()
does the following:
- Line 14 initializes
.data
to an empty list ([]
). This list will store the user’s input data. - Line 15 defines a
for
loop that iterates over the three line edits, or fields, in the dialog. - Lines 16 to 23 define a conditional statement that checks if the user has provided data for each field in the dialog. If not, then the dialog shows an error message that warns the user about the missing data.
- Line 25 adds the user’s input for each field to
.data
. - Line 30 calls the superclass’s
.accept()
slot to provide the standard behavior that closes the dialog after the user clicks OK .
With this code, you’re ready to add a new slot to the contact book’s main window. This slot will launch the dialog, and if the user provides valid input, then the slot will use the model to save the newly added contact to the database.
Launching the Add Contact Dialog
Now that you’ve coded the Add Contact dialog, it’s time to add a new slot to Window
so you can launch the dialog by clicking Add and process the user’s input once they click OK .
Go to the definition of Window
and add the following code:
1# -*- coding: utf-8 -*-
2# rpcontacts/views.py
3
4# Snip...
5class Window(QMainWindow):
6 # Snip...
7
8 def setupUI(self):
9 # Snip...
10 self.addButton = QPushButton("Add...")
11 self.addButton.clicked.connect(self.openAddDialog)
12 # Snip...
13
14 def openAddDialog(self):
15 """Open the Add Contact dialog."""
16 dialog = AddDialog(self)
17 if dialog.exec() == QDialog.Accepted:
18 self.contactsModel.addContact(dialog.data)
19 self.table.resizeColumnsToContents()
Here’s a summary of what’s happening in the above code:
- Line 11 connects the
.clicked()
signal of the Add button to the newly created slot,.openAddDialog()
. This way, a click on the button will automatically call the slot. - Line 14 defines the
.openAddDialog()
slot. - Line 16 creates an instance of
AddDialog
. - Lines 17 to 19 define a conditional statement to check if the dialog was accepted. If so, then line 14 calls
.addContact()
on the data model with the dialog’s.data
attribute as an argument. The final statement in theif
code block resizes the table view to fit the size of its updated content.
Now that you have a way to launch the Add Contact dialog and to process its data, you need to provide the code for .addContact()
in your data model. That’s a topic for the next section.
Processing the Add Dialog’s Data in the Model
In this section, you’ll add a method called .addContact()
to your data model, ContactsModel
. Open model.py
in your code editor, go to the definition of ContactsModel
, and add the following code:
1# -*- coding: utf-8 -*-
2# rpcontacts/model.py
3
4# Snip...
5class ContactsModel:
6 # Snip...
7
8 def addContact(self, data):
9 """Add a contact to the database."""
10 rows = self.model.rowCount()
11 self.model.insertRows(rows, 1)
12 for column, field in enumerate(data):
13 self.model.setData(self.model.index(rows, column + 1), field)
14 self.model.submitAll()
15 self.model.select()
Inside .addContact()
, the code does the following:
- Line 10 gets the current number of rows in the data model.
- Line 11 inserts a new row at the end of the data model.
- Lines 12 and 13 run a
for
loop that inserts every item indata
into the corresponding cell in the data model. To do this, line 9 calls.setData()
on the model, with the index of the cell and the current datafield
as arguments. - Line 14 submits the changes to the database by calling
.submitAll()
on the model. - Line 15 reloads the data from the database into the model.
If you run the application with these new additions, then you’ll get the following behavior:
Now when you click Add , the Add Contact dialog appears on your screen. You can use the dialog to provide the required information for a new contact and to add the contact to the database by clicking OK .
Step 6:Deleting Existing Contacts
The final feature you’ll add to the contact book application is the ability to remove contacts from the database using the GUI.
Again, you’ll find all the files and the code added or modified in this section under the source_code_step_6/
annuaire. You can download them by clicking the link below:
Get the Source Code: Click here to get the source code you’ll use to build a contact book with Python, PyQt, and SQLite in this tutorial.
In this section, you’ll first add the capability to delete a single contact at a time. Then you’ll add code to remove all the contacts from the database.
Deleting Selected Contacts
To remove a single contact from the contact database, you need to select the desired contact in the table view on the contact book’s main window. Once you’ve selected the contact, you can click Delete to perform the operation on the database.
Go to the model.py
module and add the following code to implement .deleteContact()
inside ContactsModel
:
# -*- coding: utf-8 -*-
# rpcontacts/model.py
# Snip...
class ContactsModel:
# Snip...
def deleteContact(self, row):
"""Remove a contact from the database."""
self.model.removeRow(row)
self.model.submitAll()
self.model.select()
This method has three lines of code. The first line removes the selected row
. The second line submits the change to the database. Finally, the third line reloads the data into the model.
Next, get back to the views.py
module and add the code behind the Delete button in Window
:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
class Window(QMainWindow):
# Snip...
def setupUI(self):
"""Setup the main window's GUI."""
# Snip...
self.deleteButton = QPushButton("Delete")
self.deleteButton.clicked.connect(self.deleteContact)
# Snip...
def deleteContact(self):
"""Delete the selected contact from the database."""
row = self.table.currentIndex().row()
if row < 0:
return
messageBox = QMessageBox.warning(
self,
"Warning!",
"Do you want to remove the selected contact?",
QMessageBox.Ok | QMessageBox.Cancel,
)
if messageBox == QMessageBox.Ok:
self.contactsModel.deleteContact(row)
In the first highlighted line, you connect the .clicked()
signal of the Delete button to the .deleteContact()
slot. This connection triggers a call to .deleteContact()
every time the user clicks the button.
In .deleteContact()
, you first get the index of the currently selected row in the table view. The if
statement checks if the index is lower than 0
, which would mean that there are no contacts in the table view. If so, then the method returns immediately without performing any further actions.
Then the method shows a warning message confirming that the user wants to delete the selected contact. If the user accepts the operation, then .deleteContact(row)
gets called. In this case, row
represents the index of the currently selected row in the table.
After these additions, you can run the application again to get the following behavior:
Now when you select a contact from the table view and click Delete , you’re presented with a warning message. If you click the message dialog’s OK button, then the application removes the selected contact from the database, updating the table view accordingly.
Clearing the Contact Database
To remove all the contacts from the database, you’ll start by adding a method called .clearContacts()
to ContactsModel
. Open your model.py
module and add the following method at the end of the class:
1# -*- coding: utf-8 -*-
2# rpcontacts/model.py
3
4# Snip...
5class ContactsModel:
6 # Snip...
7
8 def clearContacts(self):
9 """Remove all contacts in the database."""
10 self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
11 self.model.removeRows(0, self.model.rowCount())
12 self.model.submitAll()
13 self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
14 self.model.select()
Here’s what each line of code does:
- Line 10 sets the data model’s
.editStrategy
property toQSqlTableModel.OnManualSubmit
. This allows you to cache all the changes until you call.submitAll()
plus tard. You need to do this because you’re changing several rows at the same time. - Line 11 removes all the rows from the model.
- Line 12 saves changes to the database.
- Line 13 resets the model’s
.editStrategy
property to its original value,QSqlTableModel.OnFieldChange
. If you don’t reset this property to its original value, then you won’t be able to update the contacts directly in the table view. - Line 14 reloads the data into the model.
Once you’ve coded .clearContacts()
, you can get back to the views.py
file and update Window
with the following code:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
class Window(QMainWindow):
# Snip...
def setupUI(self):
"""Setup the main window's GUI."""
# Snip...
self.clearAllButton = QPushButton("Clear All")
self.clearAllButton.clicked.connect(self.clearContacts)
# Snip...
def clearContacts(self):
"""Remove all contacts from the database."""
messageBox = QMessageBox.warning(
self,
"Warning!",
"Do you want to remove all your contacts?",
QMessageBox.Ok | QMessageBox.Cancel,
)
if messageBox == QMessageBox.Ok:
self.contactsModel.clearContacts()
The first highlighted line in this code connects the .clicked()
signal of the Clear All button to the .clearContacts()
slot below.
In .clearContacts()
, you first create a message dialog, messageBox
, to ask the user to confirm the removing operation. If the user confirms the operation by clicking OK , then .clearContacts()
gets called on the model to remove all the contacts from the database:
C'est ça! With this last piece of code, your contact book application is complete. The application provides features that allow your users to display, add, update, and remove contacts from the database.
Conclusion
Building a contact book GUI application with Python, PyQt, and SQLite is an excellent exercise for you to expand your skills with these tools and as a developer in general. Coding projects like this allows you to apply the knowledge and skills you already have and also pushes you to research and learn about new topics every time you encounter a new programming problem.
In this tutorial, you learned how to:
- Build the GUI for a contact book application using PyQt
- Use PyQt’s SQL support to connect the application to an SQLite database
- Use PyQt’s Model-View architecture to work with the application’s database
You can download the complete source code for the contact book application and also the code to complete each step in this tutorial by clicking the link below:
Get the Source Code: Click here to get the source code you’ll use to build a contact book with Python, PyQt, and SQLite in this tutorial.
Next Steps
At this point, you’ve completed a fully functional contact book project. The application provides minimal functionality, but it’s a good starting point to continue adding features and take your Python and PyQt skills to the next level. Here are some next step ideas that you can implement:
-
Add new data fields: Adding new data fields to store more information about your contacts would be great. For example, you can add the contact’s photo, phone number, web page, Twitter handle, and so on. To do this, you might need to create new tables and set up relations between them. PyQt provides the
QSqlRelationalTableModel
, which defines an editable data model for a single table and provides foreign key support. -
Provide search capability: Giving your users a way to search for a contact in the database is arguably a must-have feature in this kind of application. To implement it, you can use PyQt’s
QSqlQuery
andQSqlQueryModel
. -
Add back-up capability: Providing a way of backing up contact information is another interesting feature. Users might face problems with their computers and lose their data. You can provide options to upload the data to a cloud service or to back it up to an external disk.
These are just a few ideas for how you can continue adding features to your contact book. Take the challenge and build something amazing on top of this!