Bonjour à tous,
Je présente rapidement mon projet pour lequel j'essaye de respecter le principe MCV :
J'ai une base de données que je souhaite présenter à l'intérieur d'uen QTableView. Cette table est en lecture seule. Les sélections sur cette table se font par ligne uniquement (pas de sélection de cellule seule). La sélection d'une ligne entraîne le chargement des données de la ligne dans un formulaire présent à coté du tableau (système QMapperDataWidget). Des boutons permettent d'enregistrer les modifications du formulaire, supprimer, insérer un enregistrement, ... et grâce à la magie de PyQt toutes les modifications se font automatiquement dans la base sans que je fasse rien.

Le problème qui se pose est le suivant :
Tout fonctionne correctement si je travaille sur une table complète de ma base : model.selectTable("clients"). Mais si je souhaite ne travailler que sur une partie de ma table en utilisant une requête : model.setQuery("SELECT * FROM 'clients' WHERE local=0"), les données apparaissent bien dans le TableView et dans le formulaire, si je modifie le formulaire et enregistre les données modifiées apparaissent bien dans le tableau, par contre l'enregistrement dans la base ne se fait plus.

J'ai bien tenté de créer une classe modèle en surclassant QSqlTableModel et QSqlQueryModel, mais je ne suis pas à l'aise avec cette solution et ne trouve pas d'exemples qui utilise cette technique avec une base de données. De plus je me demande si c'est une solution étant donné que mon modèle est bien modifié, mais que c'est l'enregistrement dans la base qui ne l'est pas.
Voici le code (j'ai mis un fichier SQL en fichier joint avec ma table installé sur SQLITE).

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 
import sys
from tableModel import Ui_MainWindow
from PySide6.QtSql import QSqlDatabase, QSqlTableModel
from PySide6.QtWidgets import QMainWindow, QApplication, QAbstractItemView, QDataWidgetMapper
 
 
class controler(QMainWindow):
    def __init__(self):
        super().__init__()
        self.nouvelEnregistrement = False  # à utiliser lors du click sur nouveau et annuler
 
        # ouverture d'une base de données
        self.base = QSqlDatabase.addDatabase("QSQLITE")
        self.base.setDatabaseName("test.db")
        if self.base.open():
            print(self.base.lastError())
 
        # création d'un modèle sur la table de la base
        self.model_table = QSqlTableModel()
        self.model_table.setTable("clients")
        self.model_table.select()
 
        # creation de la vue
        self.fenetre = Ui_MainWindow()
        self.fenetre.setupUi(self)
        self.fenetre.tableView.setModel(self.model_table)
 
        # options de la vue
        self.fenetre.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)  # selection de ligne uniquement
 
        # creation d'un mapper pour le formulaire
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.model_table)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)  # enregistrement par le bouton enregistrer
        self.mapper.addMapping(self.fenetre.lineEdit, 0)
        self.mapper.addMapping(self.fenetre.lineEdit_2, 1)
        self.mapper.addMapping(self.fenetre.lineEdit_3, 2)
        self.mapper.addMapping(self.fenetre.lineEdit_4, 3)
        self.mapper.toFirst()
 
        # gestion des évènements
        self.fenetre.tableView.selectionModel().selectionChanged.connect(self.on_selectionChanged_connected)
        self.fenetre.pushButton_enregistrer.clicked.connect(self.on_pushButton_enregistrer_connected)
        self.fenetre.pushButton_supprimer.clicked.connect(self.on_pushButton_supprimer_connected)
        self.fenetre.pushButton_nouveau.clicked.connect(self.on_pushbutton_nouveau_connected)
        self.fenetre.pushButton_annuler.clicked.connect(self.on_pushButton_annuler_connected)
 
        # sélection de la première ligne
        self.fenetre.tableView.selectRow(0)
 
    def on_selectionChanged_connected(self, selected, deselected):
        """
        Modification des données du formulaire en fonction de la ligne sélectionnée
        """
        self.mapper.setCurrentIndex(selected.indexes()[0].row())
        pass
 
    def on_pushButton_enregistrer_connected(self):
        """
        Enregistrement des données du formulaire
        """
        self.mapper.submit()
        self.nouvelEnregistrement = False
        pass
 
    def on_pushButton_supprimer_connected(self):
        """
        Suppression de la ligne du modèle et sélection de la ligne précédente
        """
        numLigne = self.fenetre.tableView.currentIndex().row()
        self.model_table.removeRow(numLigne)
        self.fenetre.tableView.selectRow(numLigne-1)
        self.model_table.select()
        pass
 
    def on_pushbutton_nouveau_connected(self):
        """
        Dans un premier temps, création d'une nouvelle ligne avec aucune donnée, sauf l'id qui
        est un champ clé primaire autoincrémenté dans la base, les données seront écrites
        dans le formulaire puis enregistrées
        """
        self.nouvelEnregistrement = True
        record = self.model_table.record()
        record.setGenerated("id", False)
        self.model_table.insertRecord(-1, record)
        self.fenetre.tableView.selectRow(self.model_table.rowCount()-1)
        pass
 
    def on_pushButton_annuler_connected(self):
        """
        Test pour savoir si l'enregistrement d'un nouvel enregistrement est en cours, si c'est
        le cas, on supprime la ligne.
        Puis, on sélectionne la ligne suivante et on sélectionne à nouveau la ligne en cours pour
        annuler les changements dans le formulaire
        """
        if self.nouvelEnregistrement:
            self.on_pushButton_supprimer_connected()
            self.nouvelEnregistrement = False
        indexEnCours = self.mapper.currentIndex()
        self.fenetre.tableView.selectRow(indexEnCours+1)
        self.fenetre.tableView.selectRow(indexEnCours)
        pass
 
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    fenetre = controler()
    fenetre.show()
    sys.exit(app.exec())
clients.sql