QSqlTableModel QDataWidgetMapper

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
GiJay
User
Beiträge: 36
Registriert: Freitag 5. März 2021, 14:40
Wohnort: Ratingen
Kontaktdaten:

Tach auch,

mein erste db-Anwendung :?

es gibt eine SQLite Datenbank. Um die bestehenden Datensätze zu ändern nutze ich ein Model (QSqlTableModel) und einen Mapper (QDataWidgetMapper). Dies funktioniert einwandfrei.

Jetzt möchte ich einen neuen Datensatz anhängen. Meine Überlegung:

- leeren Record erstellen
- Record am Ende der db einfügen
- Ans Ende vom Mapper gehen
- Daten ans Model übertragen
- Daten in die db eintragen

Code: Alles auswählen

 
rec = self.model.record()					
self.model.insertRecord(-1, rec)			
self.mapper.toLast()
self.mapper.submit()
self.model.submitAll()
Bis "Record am Ende der db einfügen" funktioniert es. Bekomme aber die Daten aus dem Mapper dann nicht in den Record.

Welchen Gedankenfehler mache ich?
Wie macht man das am geschicktesten?

Schon mal Danke fürs lesen
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

Ich kenne die Objekte QSqlTableModel und QDataWidgetMapper nicht, aber grundsäctlich ein paar Kommentare:
In einer Datenbank haben die Zeilen keine Reihenfolge. Ein "Anfügen am Ende" ist im Grunde ein inhaltlich falsches Vorgehen. Auch SQLite macht da keine Ausnahme. Sicher, wenn Du beispielsweise AUTOINCREMENT für den Primärschlüssel eingestellt hast, dann gibt es de facto eine solche Reihenfolge, aber das hat im Grunde nichts mit dem DB- Ansatz zu tun. Eine Datenbank wird erst bei der Ausgabe/Suche etc. sortiert, wenn nötig.

Ich würde vermuten, dass es für QDataWidgetMapper eine Methode bzw. Button gibt, die einen "zusätzlichen" Datensatz bereitstellt und zwei weitere Methoden gibt (Post/Cancel, Commit/Rollback ...), die dann angestoßen werden, wenn Du Deinen Datensatz "fertig gestellt" hast. Vielleicht ist aber auch nur das toLast im Weg, denn mit Insert müsste der den Fokus ja schon auf den eingefügten Datensatz gesetzt haben.

Aber - wie gesagt - die beiden Objektklassen kenne ich nicht, wo kommen die her? PyQt?
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

GiJay hat geschrieben: Donnerstag 19. Oktober 2023, 15:26 Tach auch,

mein erste db-Anwendung :?

es gibt eine SQLite Datenbank. Um die bestehenden Datensätze zu ändern nutze ich ein Model (QSqlTableModel) und einen Mapper (QDataWidgetMapper). Dies funktioniert einwandfrei.

Jetzt möchte ich einen neuen Datensatz anhängen. Meine Überlegung:

- leeren Record erstellen
- Record am Ende der db einfügen
- Ans Ende vom Mapper gehen
- Daten ans Model übertragen
- Daten in die db eintragen
Das ist nicht ganz richtig beschrieben (und hat, glaube ich, PyGuest auf eine falsche Fährte geführt). Du fügst den neuen Datensatz erst einmal ins Model ein, nicht in die Datenbank; am Ende schreibst Du ja auch ganz richtig "Daten in die db eintragen" - das ist ein Extra-Vorgang. Und "ans Ende vom Mapper gehen" stimmt so auch nicht. Der Mapper kennt immer nur einen Model-Satz, dieser Satz kann aber am Anfang oder am Ende des Models stehen, oder er folgt auf den im Moment aktuellen Satz usw. "Den Mapper ans Ende des Models schicken" wäre also besser.

Der ganze Witz vom QDataWidgetMapper ist doch, dass er Eingabefelder, die sich auf einen einzelnen Satz beziehen, mit wechselnden Sätzen des Models verbinden und die Daten zwischen diesen beiden Instanzen austauschen kann (von Datenbanken weiß der im übrigen schon mal gar nichts). Da Du sagst, dass das Ändern einzelner Datenbanksätze funktioniert, hast Du ja offensichtlich Eingabefelder für die Felder eines einzelnen Datensatzes, sonst wäre der Mapper ja sowieso sinnlos.

Es ist ganz richtig, dass nach "self.mapper.toLast()" diese Eingabefelder mit dem letzten Satz des Models verbunden sind (nicht mit dem letzten Satz der Datenbank, über den man im Normalfall tatsächlich nichts weiß). Nur: in Deinem Code wird der neue, leere Satz erzeugt, ans Model angehängt und dann wird sofort "self.mapper.submit()" aufgerufen. Hast Du in diesem Augenblick schon die neuen Werte in Deinen Eingabefeldern stehen? Es ist ein bisschen schade, dass Du Dich zu dieser Seite der Sache gar nicht äußerst.

Code: Alles auswählen

 
rec = self.model.record()					
self.model.insertRecord(-1, rec)			
self.mapper.toLast()
self.mapper.submit()
self.model.submitAll()
Bis "Record am Ende der db einfügen" funktioniert es. Bekomme aber die Daten aus dem Mapper dann nicht in den Record.

Welchen Gedankenfehler mache ich?
Wie macht man das am geschicktesten?
Der naheliegende Weg (den ich, glaube ich, aus einem guten Lehrbuch zu PyQt4 habe): die beiden Vorgänge "Neuen, leeren Satz erzeugen" und "den aktuellen, fertig belegten Satz an die Datenbank schicken" werden als zwei getrennte Methoden implementiert und getrennt aufgerufen (zwei Schalter, zwei Menüeinträge, was auch immer). Der zweite Teil kann für neue und geänderte Sätze benutzt werden. Die Trennlinie wäre zwischen "self.mapper.toLast()" und "self.mapper.submit()". Mindestens die letztere Methode gibt übrigens True oder False zurück und das kann man abfragen und evtl. darauf reagieren.

Ach ja, und wie vielleicht schon klar geworden ist: wir reden hier tatsächlich von PyQt.
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

bb1898 hat geschrieben: Montag 6. November 2023, 16:51 Es ist ganz richtig, dass nach "self.mapper.toLast()" diese Eingabefelder mit dem letzten Satz des Models verbunden sind (nicht mit dem letzten Satz der Datenbank, über den man im Normalfall tatsächlich nichts weiß). Nur: in Deinem Code wird der neue, leere Satz erzeugt, ans Model angehängt und dann wird sofort "self.mapper.submit()" aufgerufen. Hast Du in diesem Augenblick schon die neuen Werte in Deinen Eingabefeldern stehen? Es ist ein bisschen schade, dass Du Dich zu dieser Seite der Sache gar nicht äußerst.
Da war ich jetzt schlampig - Nachsehen in der Dokumentation sollte man immer zuerst und nicht hinterher: "self.mapper.toLast()" füllt die Eingabefelder mit den Daten des letzten Model-Satzes, also sind sie leer - selbst wenn Du vorher etwas hineingeschrieben hättest. Und das wird dann sofort mit "self.mapper.submit()" ans Model zurückgeschickt. Kann nichts werden.
GiJay
User
Beiträge: 36
Registriert: Freitag 5. März 2021, 14:40
Wohnort: Ratingen
Kontaktdaten:

Vielen Dank - ist gelöst !

Code: Alles auswählen


self.open_db()

self.mapper.submit()
k_rec = self.model.record()

row = self.model.rowCount()
self.model.insertRecord(row, k_rec)

row = self.model.rowCount()-1
self.model.updateRowInTable(row, k_rec)

self.model.submitAll()

self.db.close()


So funktioniert es. Ich habe tatsächlich versucht in einen nicht existierenden Record zu schreiben. :oops: Mit "row -1 " klappt es.

Was ich jetzt nicht verstehe:
Lasse ich den Code laufen und halte parallel einen DB-Viewer offen, kann ich dort die Ausführung von "insertRecord" sofort beobachten: Ein Datensatz angelegt.
Bei "updateRowInTable" muss ich erst die DB schließen, damit ein Eintrag stattfindet.
(Stört mich nicht, aber habe ich erst gemerkt, als sich nichts tat, ich die Code-Ausführung abbrach und plätzlich der Eintrag im db-Viewer erschien.)
Antworten