GUI – 38 Eingabefelder und 38 Beschriftungen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo Nutzer!

Mit dem Python-Modul tkinter spreche ich eine MySQL-Datenbank an. Funktionen wie „lies aus“, „füge hinzu“, „aktualisiere“, „lösche“ etc. funktionieren. Aber nach Schließen der tkinter-GUI ist die Datenbank wieder im Urzustand, d.h. hinzugefügte Datensätze sind weg, gelöschte sind wieder da, aktualisierte sind im Vorzustand. Wie kann das sein? Gibt es bei MySQL eine Art Testmodus, den ich deaktivieren müsste? Oder einen Cache, der geleert wird?

Grüße
Strawk
:)
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das Stichwort lautet höchstwahrscheinlich: commit.

Zeig' mal deinen Code, der in die DB schreibt. Welche Datenbanktyp nutzt du bei MySQL?

Gruß, noisefloor
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Code: Alles auswählen

"""
database functionality for live record project 
"""

import mysql.connector

    
class LiveRecordDatabase:
    def __init__(self):
        try:
            self.connection = mysql.connector.connect \
            (host = "localhost", user = "root", passwd = "", db = "firma")
            print "Established connection to database server"
        except:
            print "Connection to database server could not be established"
    
    def __del__(self):
        self.connection.close()
        
    
    def dbqueryNachKriterienAnzeigen(self, entry_value_dict, database_name="dauner"):
        # abfrage string zusammenbauen
        itemlist = ["%s LIKE %s" %(key, decorate(value)) for key,value in entry_value_dict.iteritems() if not value=='']
        item_str = " AND ".join(itemlist)
        sql_abfrage_str = "SELECT * from %s where %s" % (database_name, item_str)
        
        # abfrage machen
        cursor = self.connection.cursor()
        cursor.execute(sql_abfrage_str)

        # Daten auslesen
        sql_ergebnis = cursor.fetchall()

        # Execution-Objekt schliessen
        cursor.close()
        
        ausgabe_gegliedert_all = []
        # SQL Abfrageergebnis formatieren
        for item in sql_ergebnis:
            item_uc = [unicode(el) for el in item]
            header = " ".join(item_uc[0:5])
            body = " ".join(item_uc[5:])
            ausgabe_gegliedert = header + "\n" + body + "\n\n"
            ausgabe_gegliedert_all.append(ausgabe_gegliedert)
        
        return ausgabe_gegliedert_all

        
    def dbqueryLiesInMaskeEin(self, number_single_record):
        sql_abfrage_str = "SELECT * from dauner where nummer = %s" % (number_single_record)
        # print sql_abfrage_str
        
        # abfrage machen
        cursor = self.connection.cursor()
        cursor.execute(sql_abfrage_str)

        # Daten auslesen
        sql_ergebnis = cursor.fetchall()

        # Execution-Objekt schliessen
        cursor.close()
        
        # print sql_ergebnis
        
        return sql_ergebnis
        
    def dbqueryFuegeMenschHinzu(self, entry_value_dict):
        abfrage  = "INSERT INTO dauner ("
        for key, value in entry_value_dict.items():
            if value != "":
                abfrage = abfrage + key + ", "
        abfrage = abfrage[:-2]
        abfrage = abfrage + ")"
        abfrage = abfrage + " VALUES " + "("
        for key, value in entry_value_dict.items():
            if value != "":
                abfrage = abfrage + "'" + value + "', "
        abfrage = abfrage[:-2]
        abfrage = abfrage + ")"
            
        # return abfrage
        # abfrage machen
        cursor = self.connection.cursor()
        cursor.execute(abfrage)

        # Execution-Objekt schliessen
        cursor.close()
        
    def dbqueryAktualisiereMensch(self, number_single_record, entry_value_dict):
        abfrage = "UPDATE dauner SET "
        for key, value in entry_value_dict.items():
             if value != "":
                 abfrage = abfrage + key + "=" + "'" + value + "'" + ', '
        abfrage = abfrage = abfrage[:-2]
        abfrage = abfrage + " WHERE nummer = " + number_single_record
        
        # abfrage machen
        cursor = self.connection.cursor()
        cursor.execute(abfrage)

        # Execution-Objekt schliessen
        cursor.close()
        
    def dbqueryLoescheMensch(self, number_single_record):
        abfrage  = "DELETE FROM dauner WHERE nummer = " + number_single_record
        
        print abfrage
        # abfrage machen
        cursor = self.connection.cursor()
        cursor.execute(abfrage)

        # Execution-Objekt schliessen
        cursor.close()
        
# Utility functions        
# put "'%" and "%'" around a string, e.g. "Meyer" -> "'%Meyer%'"
def decorate(s):
    return "'%" + s + "%'"
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

sofern deine Datenbank nicht für den Autocommit-Modus konfiguriert ist fehlt bei allen Schreiboperation das `comit()`. Bei dir wird in der Tat nichts in die DB geschrieben.

Des weiteren solltest du mal über den Einsatz eines Object Relational Mappers (ORM) wie z.B. PeeWee oder SQLAlchemy nachdenken. Das String-Gestückel, was du veranstaltest, ist ziemlich gruselig.

String formatiert man mit der Format-Methode, nicht mit `+`. Methodennamen schreibt man per Konvention klein_mit_unterstrich, nicht camelCaseSchreibWeise. Nackte try...except nicht nutzen, weil du damit _alle_ Fehler abfängst, inkl. Programmierfehler. Fehler fängt man gezielt ab. Du hast kein Garantie, dass `__del__` in deiner Klasse aufgerufen wird, von daher solltest du die Verbindung zur DB explizit schließen. Bzw. wenn du ein ORM benutzt kümmert sich normalerweise das Connection-Pooling darum.

Gruß, noisefloor
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Strawk: niemals Werte für SQL-Abfragen direkt in den String hineinformatieren. Dafür gibt es Platzhalter. Wenn Du Query-Strings anfängst, von Hand zusammenzubauen, solltest Du dringend auf ein ORM-System umsteigen (SQLalchemy). Ein `if not value ==''` schreibt man als `if value != ''` oder wenns geht `if not value`. Niemals *-Select benutzen. Wenn Du irgendwann die Datenbank umbaust, wirst Du vor lauter unentdeckten Fehlern verzweifeln. Wenn Du die Anzahl der Felder kennst, benutze .format statt join. Die Methodennamen sind alle schlecht. das Präfix dbquery ist in der hälfte der Fälle falsch, in der anderen überflüssig. Methodennamen schreibt man klein_mit_unterstrich. Angezeigt wird in der Methode auch nichts, sondern nur eine Liste mit seltsam formatiertem Inhalt zurückgegeben. ListInMaskeEin liest auch nichts in eine Maske, sondern liefert einfahc einen Datensatz. `nummer` wird bei Datenbanken meist `id` genannt. In dbqueryFuegeMenschHinzu kann kein Mensch dieses Stringzusammengefrickel lesen. Werte so in SQL-Statements einzubinden ist sehr gefährlich. Damit zerschießt man sich aus Versehen oder mit Absicht die gesamte Datenbank. Menschen haben die ungewöhnlichsten Vornamen (https://xkcd.com/327/). Nimm den Mechanismus, den die Datenbankschnittstelle für das Übertragen von Parametern vorsieht. Gib immer an, welche Felder Du konkret in der Datenbank ändern willst.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nicht, das wir in diesem Thread genau dieses Thema schon vor Monaten diskutiert haben...

viewtopic.php?f=1&t=41682&start=60#p319041

Inklusive aller Hinweise auf korrekte Erstellung von SQL, String Formatierung etc. Das ist offensichtlich wirkungslos.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo wieder! :)
Ist euch das Buch:

Albert Lukaszewski: MySQL for Python. Integrate the flexibility of Python and the power of MySQL to boost the productivity of your applications. Birmingham: PACKT publishing 2010

bekannt? Wenn ja, ist es gut?

Grüße
Strawk
:?:
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

es ist mir nicht bekannt, aber in den letzten 8 Jahren haben sich bei MySQL und Python einige Sachen geändert, im Sinne von dazu gekommen, verbessert etc. Von daher muss man bei so "alten" Bücher immer genauer hin schauen, wie viel heute noch gilt bzw. ob es heute nicht bessere / neuere Wege gibt.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Die Frage ist auch ob in so einem Buch SQLAlchemy Thema ist — sonst sehen wir hier am Ende weiterhin dieses furchtbare SQL-Anfragen aus Zeichenketten zusammenstückeln.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Strawk: durch Drüberscrollen ist die Qualität wie üblich bei diesen Büchern, mäßig. Warum bei `SELECT *` der * mit regulären Ausdrücken in Verbindung gebracht wird, läßt nur vermuten, dass da jemand per Copy-Paste was zusammenkopiert hat, ohne den Inhalt zu verstehen.
Ansonsten ist das mehr oder weniger die Dokumentation kopiert, mit wenig oder irreführenden Erklärungen. `ALL` soll synonym für `*` sein? `execute(..)` lädt alle Ergebnisse ins RAM?
Dann die übliche NoGo`s mit SELECT * -> fetchall und dann einer for-Schleife. Natürlich werden Parameter direkt in das SQL-Statement hineinformatiert! Also schlechte Beispiele aus dem Internet in Buchform. Dem Alter geschuldet sind die Beispiele in Python2, inklusive nackter Excepts, for-Schleifen über Indizes; Code der überkomplex ist und nicht mal funktioniert.
Zu den positiven Aspekten zählt, dass es wenigstens ein Kapitel über Exceptionhandling gibt.
Daher für den Python-Part eine 6+ mit zwei zugedrückten Augen. Und für den MySQL-Part eine 5-, weil beim Abschreiben der Dokumentation sich das Hinzufügen von Fehlern in Grenzen hielt.

MySQL lernt man besser mit den Tutorials in der MySQL-Dokumentation, und für die Python-Anbindung solltest Du SQLAlchemy benutzen.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo Sirius3!

Danke für die ausführliche Kritik! Hast mir geholfen.

Strawk
Ich programmiere erfolglos, also bin ich nicht.
Antworten