PyQt: Welche Datenbank, MariaDB klappt nicht ?

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
mephisto-online
User
Beiträge: 167
Registriert: Sonntag 29. September 2013, 17:05

Hallo,
schreibe gerade eine etwas umfangreichere Desktop-App mit PyCharm unter Manjaro-Linux mit PyQt und komme wegen der genialen Unkompliziertheit von Python und Qt super vorran.

Jetzt geht es darum, Daten, die momentan über Files gehändelt werden, in einer Datenbank zu halten. Das Ganze hatte ich früher schon unter C# mit einer MSSQL-Datenbank realisiert und eigentlich wollte ich die Daten jetzt auch aus dieser Datenbank übernehmen, wovon ich aber abgekommen bin, da ich mich mit Datenbanken nicht so sonderlich (eigentlich gar nicht ...) auskenne und einen Export nach MySQL nicht hinbekommen habe.

Also werde ich jetzt alles von Grund auf neu aufbauen und die Daten dann aus den Files in die neue Datenbank einlesen (es handelt sich um maximal 100 Datensätze).

Jetzt habe ich versucht, mit QtSql auf eine einfache MariaDB-Test-Datenbank zuzugreifen und erhalte immer den Fehler: "Driver not loaded Driver not loaded", obwohl db.drivers() "['QSQLITE', 'QSQLITE3', 'QMYSQL3', 'QMYSQL', 'QODBC3', 'QODBC', 'QPSQL7', 'QPSQL']" ausgibt.

Mein Test-Programm aus einem Beispiel:

Code: Alles auswählen

from PyQt4.QtGui import *
from PyQt4.QtSql import *
import sys

def main():
    app = QApplication(sys.argv)
    table = QTableWidget()
    table.setWindowTitle("Connect to Mysql Database Example")
    db = QSqlDatabase()
    db.addDatabase("QMYSQL")
    db.setHostName("localhost")
    db.setDatabaseName("test")
    db.setUserName("root")
    db.setPassword("password")

    if not db.open():
        QMessageBox.critical(None, "Database Error", db.lastError().text())
    print(db.lastError().text())
    print(db.drivers())
    query = QSqlQuery(db)
    query.exec("SELECT * FROM test")
    table.setColumnCount(query.record().count())
    table.setRowCount(query.size())

    index = 0
    while query.next():
        table.setItem(index, 0, QTableWidgetItem(query.value(0).toString()))
        print(QTableWidgetItem(query.value(0).toString()))
        table.setItem(index, 1, QTableWidgetItem(query.value(1).toString()))
        index += 1

    table.show()

    return app.exec_()
if __name__ == '__main__':
  main()
Bei der Ausführung erhalte ich die Meldung: "QSqlQuery::exec: database not open", das QTableWidget bleibt leer.

Wegen der Einfachheit meiner Daten (eine Tabelle mit momentan ca. 25 Columns) frage ich mich, ob nicht erst mal mit einer, wohl auch von Qt gut supporteten SQLite-Datenbank arbeiten sollte. Ich weiss aber nicht, ob ich irgendwann doch Relationen und mehrere Tabellen brauche und ob ich dann die SQLite-Datenbank problemlos in eine MariaDB-Datenbank exportieren (oder anders herum importieren) kann.

Einem Tip aus diesem Forum zufolge würde u.U. auch der Einsatz von SQLAlchemie sinnvoll sein.

Momentan bin ich da ein wenig ratlos. Vielleicht kann mir ja hier jemand ein paar Tips geben ?

Grüße
mephisto-online
BlackJack

@mephisto-online: Du erzeugst das `QSqlDatabase`-Exemplar falsch. Die Klasse ist ein wenig komisch denn wenn man einfach so ein Objekt davon erstellt bekommt man keine Verbindung sondern ein Objekt mit dem man Verbindungen erzeugen kann, beide „Arten” von Objekten haben aber den selben Typ: `QSqlDatabase`. Finde ich persönlich ja ein wenig schräg, aber vielleicht ist das ja irgendwie so ein „C++ Ding”.

Ich würde den einfachsten Weg gehen der in der Dokumentation als Beispiel steht und die statische Methode `QSqlDatabase.addDatabase()` verwenden um das Verbindungsobjekt zu erstellen. Also:

Code: Alles auswählen

    #
    # Falsch, bzw. nicht ausreichend:
    # 
    database = QSqlDatabase()
    database.addDatabase('QMYSQL')
    # 
    # Richtig, bzw. der kürzeste Weg an ein gültiges `QSqlDatabase`-Exemplar:
    # 
    database = QSqlDatabase.addDatabase('QMYSQL')
mephisto-online
User
Beiträge: 167
Registriert: Sonntag 29. September 2013, 17:05

@BlackJack
Jo, das funzt ! Danke vielmals !
:)
BlackJack hat geschrieben:Die Klasse ist ein wenig komisch denn wenn man einfach so ein Objekt davon erstellt bekommt man keine Verbindung sondern ein Objekt mit dem man Verbindungen erzeugen kann.
und wie würde man die dann erzeugen ? Oder geht das einfach nicht ?
BlackJack hat geschrieben:...beide „Arten” von Objekten haben aber den selben Typ: `QSqlDatabase`. Finde ich persönlich ja ein wenig schräg, aber vielleicht ist das ja irgendwie so ein „C++ Ding”.
Ja, mir kommt das ganze C++ ein wenig schräg vor ! Aber ich bin ja auch nicht "eingeweiht"... :lol:

Aber da es ja jetzt geht, könnte ich ja theoretisch jetzt starten. :P

Aber nochmal die Frage: Macht es Sinn, direkt mit der MariaDB zu starten oder könnte ich auch erst mal mit SQLite anfangen ? SQLite hätte den Vorteil, dass ich mein Programm dann auch irgendwann (ohne viel Gedöhns) auf Android portieren könnte. Relationen werde ich aber irgendwann mal auf dem Desktop brauchen, aber nicht unbedingt auf dem Mobile. Wenn ich die SQLite-DB aber problemlos in eine MariaDB überführen könnte, würde ich jetzt erst mal mit SQLite anfangen.

Und ob es Sinn machen würde, direkt die SQLAlchemie-Packages zu verwenden, würde mich auch brennend interessieren. Dieses Mal möchte ich mir halt möglichst keine Wege verbauen :shock: . Und mir dem Datenbank-Geschnätz kenne ich mich (noch) nicht richtig aus. :oops:

Viele Grüße
mephisto-online
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@mephisto-online: Du erzeugst Dir ja ein Datenbankobjekt, nur nicht über einen Konstruktor sondern durch eine Factory-Methode. Solange nicht mehrere Programme gleichzeitig auf eine Datenbank zugreifen, ist SQLite die bessere Wahl. Jede Datenbank hat ihre Stärken und Schwächen, aber solange man nichts exotisches macht und sich an den SQL-Standard hält, können alle das Gleiche. Ehrlich gesagt, weiß ich nicht, welchen Vorteil es überhaupt hat, die in Qt integrierte Datenbankschnittstelle zu benutzen. Logik und GUI sollten ja möglichst getrennt sein, und Datenhaltung gehört eindeutig zur Logik.
mephisto-online
User
Beiträge: 167
Registriert: Sonntag 29. September 2013, 17:05

@Sirius3
Sirius3 hat geschrieben:...Solange nicht mehrere Programme gleichzeitig auf eine Datenbank zugreifen, ist SQLite die bessere Wahl.
Ja, ich erinnere mich, SQLite kann nur eine Session. :oops:
Sirius3 hat geschrieben:Jede Datenbank hat ihre Stärken und Schwächen, aber solange man nichts exotisches macht und sich an den SQL-Standard hält, können alle das Gleiche.
Da werden sicherlich keine "exotischen" in meinem Programm erforderlich sein, alles "general purpuse", SQL-Reinkultur. 8)

Aber vielleicht könnt Ihr mir ja auch noch ein paar Aspekte bezüglich der "Ineinander-Überführbarkeit" (welche z.B. bei einer MSSQL-Datenbank nicht so ganz einfach gegeben ist) aufzeigen. Das wäre für mich im Moment schon sehr wichtig. :wink:
Sirius3 hat geschrieben:...Ehrlich gesagt, weiß ich nicht, welchen Vorteil es überhaupt hat, die in Qt integrierte Datenbankschnittstelle zu benutzen. Logik und GUI sollten ja möglichst getrennt sein, und Datenhaltung gehört eindeutig zur Logik...
Das sage ich mir eigentlich auch. Deshalb frage ich mich ja, welche Schnittstelle ich nutzen sollte, die von Python (damit habe ich es schon probiert und funktioniert...) oder besser gleich das SQLAlchemy-Interface. Es macht mir nichts aus, mich nun auch noch in SQLAlchemy einzuarbeiten, wenn mir das in der Zukunft das Leben einfacher machen könnte.

Grüße
mephisto-online
BlackJack

@mephisto-online: Der umständlichere Weg über ein Exemplar von `QSqlDatabase` an eine Verbindung zu kommen geht so:

Code: Alles auswählen

    database_factory = QSqlDatabase()
    database_factory.addDatabase('QMYSQL')
    database = database_factory.database()
Relationen gehen mit jeder SQL-Datenbank, denn das ist ja eine Abfragesprache für relationale Datenbanken. Wenn man nichts zu spezielles von einem bestimmten Datenbanksystem verwendet, kann man die Datenbank relativ einfach austauschen.

Die Qt-Klassen für SQL-Datenbanken machen Sinn wenn man damit einfacher die Daten in die GUI bekommt. Falls man das nicht nutzen kann oder will, dann kann man auch andere Bibliotheken verwenden.

@Sirius3: Qt-Klassen sind ja nicht alle GUI-bezogen. Das stellt für C++ eine ganze „Standardbibliothek” bereit. Und bei SQL aber auch eine Verbindung zur GUI mit Klassen die Tabellen einfach über eine Model-Klasse die SQL-Tabellen in einen View bringen können. Wenn man hauptsächlich die Tabelle relativ direkt in eine Tabelle in der GUI anbieten will, geht das damit einfacher als wenn man das alles von Hand schreiben würde.
mephisto-online
User
Beiträge: 167
Registriert: Sonntag 29. September 2013, 17:05

Hallo,
@BlackJack
BlackJack hat geschrieben:Der umständlichere Weg über ein Exemplar von `QSqlDatabase` an eine Verbindung zu kommen geht so:

Code: Alles auswählen

    database_factory = QSqlDatabase()
    database_factory.addDatabase('QMYSQL')
    database = database_factory.database()
Geht also doch, man muss es nur wissen ! Wo bekommst Du denn solche Infos her ? C++ ?
BlackJack hat geschrieben:Relationen gehen mit jeder SQL-Datenbank, denn das ist ja eine Abfragesprache für relationale Datenbanken. Wenn man nichts zu spezielles von einem bestimmten Datenbanksystem verwendet, kann man die Datenbank relativ einfach austauschen.
Mutigerweise habe ich jetzt direkt mit der MariaDB angefangen und bisher funktioniert es ganz gut (nur phpmysql nervt ..., nicht so sehr intuitiv, gibt es da nichts Besseres, vielleicht ohne Webserver und Browser ? Bin doch nicht im Internet :( ).
BlackJack hat geschrieben:Die Qt-Klassen für SQL-Datenbanken machen Sinn wenn man damit einfacher die Daten in die GUI bekommt. Falls man das nicht nutzen kann oder will, dann kann man auch andere Bibliotheken verwenden.
Da bin ich ja beruhigt ! Die Qt-Klassen finde ich nämlich einfach Spitze ! Das gleiche ging in .NET/C# zwar auch schon ganz gut, aber nicht so gut wie mit Qt.

Vielen Dank !
mephisto-online

P.S.: Warum habt Ihr hier eigentlich Greenwich-Uhrzeit ?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

mephisto-online hat geschrieben:Geht also doch, man muss es nur wissen ! Wo bekommst Du denn solche Infos her ? C++ ?
Aus der Dokumentation zu Qt. Du musst sie halt lesen ;-)
Das Leben ist wie ein Tennisball.
mephisto-online
User
Beiträge: 167
Registriert: Sonntag 29. September 2013, 17:05

@Blackjack
Wieder was gelernt ! Hatte immer versucht, mit der PyQt-Doku von Riverbank weiter zu kommen. Also doch ein wenig C++ lernen :shock: , und wenn es nur das Lesen ist ... :roll:
EmaNymton
User
Beiträge: 174
Registriert: Sonntag 30. Mai 2010, 14:07

Vielleicht noch als Ergänzung: Wenn du öfters was mit Datenbanken machen willst, lohnt es imho sich das Model-View-Konzept anzuschauen, da man dein Programm mit einer TableView statt einem TableWidget wesentlich kürzer formulieren kann. Qt liefert da auch für die verschiedenen Anwendungsfälle fertige Modells (QSqlQueryModel, QSqlTableModel, QSqlRelationalTableModel), so dass man sich im Prinzip gar nicht mehr um die Darstellung der Daten kümmern muss. Das was du im Prinzip in deiner while-Schleife machst, wird dir vom Model abgenommen und reduziert sich auf eine Zeile (Zeile 23):
[codebox=python file=Unbenannt.txt]
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt4.QtGui import *
from PyQt4.QtSql import *
import sys

def main():
app = QApplication(sys.argv)
db = QSqlDatabase.addDatabase('QMYSQL')
db.setHostName("localhost")
db.setDatabaseName("test")
user = "root"
password = "password"
tableview = QTableView()
tableview.setWindowTitle("Connect to Mysql Database Example")
sql_query_model = QSqlQueryModel()
tableview.setModel(sql_query_model)

if not db.open(user, password):
QMessageBox.critical(None, "Database Error", db.lastError().text())

sql_query_model.setQuery("SELECT * FROM test", db)

tableview.show()

return app.exec_()

if __name__ == '__main__':
main()
[/code]
Benutzeravatar
ngulam
User
Beiträge: 35
Registriert: Freitag 18. Oktober 2013, 11:03

EmaNymton hat geschrieben:Model-View-Konzept anzuschauen
...und das klappt sehr wohl auch mit MariaDB
Mein System hat geschrieben:Server version: 5.5.33-MariaDB openSUSE package
Python 3.3.2 (default, Jun 13 2013, 16:05:31) [GCC]
openSuSE x86_64 Linux 3.11.6-4-desktop
งูหลาม
mephisto-online
User
Beiträge: 167
Registriert: Sonntag 29. September 2013, 17:05

EmaNymton hat geschrieben:Vielleicht noch als Ergänzung: Wenn du öfters was mit Datenbanken machen willst, lohnt es imho sich das Model-View-Konzept anzuschauen, da man dein Programm mit einer TableView statt einem TableWidget wesentlich kürzer formulieren kann.]
Danke Dir (und Euch)! Das fängt ja an richtig Spass zu machen. Tja, so einfach kann sowas sein !

Wenn ich da an ,NET zurückdenke ! War auch schon noch viel einfacher als mit Java, aber mit PyQt ist das ja echt noch wesentlich unkoplizierter. Warum einfach, wenn es auch kompliziert geht ! :lol:

Ich nehme mal an, dass sich das o.g. mit SQLite ähnlich darstellt. Habe nämlich gerade mein Konzept geändert und möchte nun in meinem Programm alternativ mit einer SQLite-DB und einer Maria-DB arbeiten (mit programmatischem Abgleich), je nachdem, ob ich online bin (oder im Netz) oder offline unterwegs.

Grüße
m-o
Antworten