Anfängerfragen zu Python und MySQL

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hey Leute,

    ich hab mir mal wieder ein paar Gedanken gemacht und bin leicht am verzweifeln, weil das Python Programm nicht das macht, was es soll.

    Erstmal zu der Aufgabenbeschreibung des Programmes:

    Das Programm soll in der Aktuellen Version lediglich eine MySQL Datenbank abfragen, ob ein Bestimmter Datensatz enthalten ist und diesen soll er danach dann ausgeben. Idealerweise wäre super, wenn ich die Ausgabe in entsprechende Variablen bzw. einem Array speichern kann und diesen dann Aufteilen kann um eine schönere Ausgabe hin zu bekommen.

    Das Programm soll aber auf Dauer noch um ein paar Funktionen erweitert werden. Und zwar soll es möglich sein, Datensätze zu verändern. Aber das kommt später.

    Erst einmal der Code, welchen ich mir durch verschiedene Tutorials und Co zusammengeklöppelt habe:

    Dieser Code löst folgende Fehlermeldung aus:

    Code
    Bitte Barcode scannen: 4008153003578
    Traceback (most recent call last):
      File "mysql.py", line 12, in <module>
        cursor.execute("SELECT * FROM warenlager WHERE barcode LIKE c")
      File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 174, in execute
        self.errorhandler(self, exc, value)
      File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
        raise errorclass, errorvalue
    _mysql_exceptions.OperationalError: (1054, "Unknown column 'c' in 'where clause'")

    Die Nutzung des Barcodescanners habe ich bereits vorher mit einer If - Abfrage getestet und das Klappt. Nun wollte ich aber keine irre Lange Konfigurationsdatei erstellen, wenn man doch so einfache Dinge wie eine MySQL Datenbank nutzen kann. Zumindest war das der erste Gedanke gewesen.

    Es kann der Code ruhig als "Basis" genutzt werden um zu helfen. Wenn man aber was verbessern kann durch neuerstellung habe ich kein Problem damit.

    In der Vergangenheit habe ich schon öfter mit MySQL Datenbanken gearbeitet, aber da war die Programmiersprache aber nicht Python sondern PHP gewesen.

    Ich hoffe mir ist zu helfen :helpnew:


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

  • Hallo,

    das tut's nicht, weil der SQL-Query "SELECT * FROM warenlager WHERE barcode LIKE c" _genau_so_ ausgeführt wird - da wird keine Ersetzung im String durchgeführt. Das muss du selber machen, z.B. so:

    cursor.execute("SELECT * FROM stocks WHERE barcode = '%s'" % c)

    Das LIKE als Operator ist IMHO auch unsinnig, weil der Barcode doch _genau_ passen soll, oder? Dann nimmst du auch direkt das = .

    Und je nach dem wie dein Code weitergeht nicht vergessen, die connection wieder zu schließen.

    Und noch ein Tipp: wenn du "mehr" mit Datenbanken und Python machst, dann ist die Verwendung eines ORM (Object Relational Mapper) eine gute Idee. Unter Python heißt das: SQLAlchemy. Auch wenn es am Anfang kompliziert erscheint (ist es eigentlich nicht): ein ORM hat bei komplexeren Programmen massive Vorteile.

    Gruß, noisefloor

  • So zumindest gibt er keine Fehlermeldung. Aber leider auch keine Ausgabe. Habe ich da ggf. eine Codezeile beim letzten löschen und korrigieren evtl. vergessen.

    Kann mir jemand eine Idee geben, warum das ist?

    Und dieses ORM ist das eine Art "Funktionsumfang" oder wie genau? Weil wie gesagt, die Tabelle hat folgende Spalten Barcode, Bezeichnung, Menge und Sollmenge. Diese sollen jeweils abrufbar sein. Also auch in der Ausgabe am Ende um ein schönere Übersicht hin zu bekommen, sowie später auf einem Textdisplay eine schöne Ausgabe hin zu bekommen.

    Dadrüber hinaus gibt es eine Möglichkeit, die Connect Daten aus zu lagern? Also bei PHP kann man dies ja per Include machen. So kann ich den Code direkt ins Forum übertragen ohne immer zu überlegen ob man alles nötige Unkentlich gemacht zu haben.


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

    Einmal editiert, zuletzt von RaspiDo (22. Februar 2015 um 19:20)

  • Hallo,

    du bekommst kein Ergebnis, weil du `cursor.fetchall()` an keine Variable bindest :)

    Hier mal ein komplettes Beispiel mit SQLite. Sollte aber auch mit MySQL bzw. dem MySQLdb-Modul funktionieren. Wobei ich nicht (mehr) weiß, ob MySQLdb auch den ?-Platzhalter unterstützt. MySQLdb ist nämlich ein bisschen "sonderbar", was die Umsetzung der Python DB API 2.0 angeht...

    Bzgl. des ORM: ein ORM mappt halt DB-Tabellen auf Objekte, wodurch den DB-Zugriff "pythonischer" wird. Du kommst dann mit SQL gar nicht mehr in Berührung. Eine gute Einführung ist das SQLAlchemy-Tutorial: http://docs.sqlalchemy.org/en/rel_0_7/orm/tutorial.html.

    Ob du jetzt wirklich ein ORM brauchst oder nicht musst du selber entscheiden. Bei "größeren" Projekten ist es jedenfalls quasi "normal".

    Gruß, noisefloor

  • noisefloor: Danke für den Code, nur mit MySQL funktioniert der Code so nicht.

    Aber zu dem anderen Code, wie bekomme ich 'cursor.fetchall()' in eine Variable? Normal wäre das ja 'a = cursor.fetchall()' oder?

    Nur wenn ich das richtig verstehe, wäre 'a' ja ein Array, Stimmt's? Wie bekomm ich das den im Detail dann hin? Weil normal Kann ich ja Array Elemente durch a[1] z.B. aufrufen. Oder verstehe ich da was falsch?

    Den eine Ausgabe bekomme ich von 'cursor.fatchall()', sobald ich ein Print davor packe. Nur Sieht die Ausgabe nicht sonderlich schön aus.


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

  • Danke für den Tipp. Ich google auch parallel noch dazu und finde das ein oder andere mit Mühe auch selbst. Aber danke für den Tipp bzw. auch den Hinweis.

    Meine Lösung sieht wie folgt aus:

    Code
    rows = cursor.fetchall()
            for row in rows:
                    print "Barcode:      ", row[0]
                    print "Beschreibung: ", row[1]
                    print "Bestand:      ", row[2]
                    print "Sollbestand:  ", row[3]
                    print ""

    Habe das ganze sogar noch um eine Abfrage erweitert, ob überhaupt der Barcode bekannt ist. Dies funktioniert über:

    Code
    abfrage = cursor.execute("SELECT * FROM warenlager WHERE barcode = '%s'$
    
    
            if abfrage == 0:
                    print "Barcode unbekannt"
                    print ""

    Ich finde ich komme schon mal gut vorran. Zurzeit ist die Auswahl, was ich erledigen möchte noch über die Eingabe von Zahlen zwischen 0 und 3 realisiert. Aber auf Dauer soll ein Hardwareschalter (vermutlich Drehschalter) realisiert werden. Wobei die 0 über ein Taster oder so realisiert werden soll.

    Zusätzlich soll das Programm noch die Funktion bekommen, eine Email an zu fertigen, sobald eine Ware unter dem Sollwert kommt. Also das man vor dem Einkauf kurz ein Taster drückt, dieser stellt eine Einkaufsliste dann zusammen, mit dem Was unterm Soll ist. Zusätzlich soll man aber über eine Homepage abfragen können, was vorhanden ist.

    Die Zahlen stehen für folgendes:

    0 = Exit
    1 = Abfragen
    2 = Einlagern
    3 = Entnehmen

    Das Abfragen habe ich in eine eigene Funktion gepackt. Soll auf Dauer ja übersichtlich bleiben. Jetzt würde ich gerne Punkt 2 und 3 in Angriff nehmen. Wenn jemand ein Tipp hat, gern her damit.

    Normal müsste es ja mit dem UPDATE Befehl von MySQL laufen. Da ich ja eine Konstante habe. In Zukunft werde ich das System aber noch ein wenig aufblähen müssen, da ich z.B. Milch ja nicht immer im Laden A kaufen, sonder auch mal in Laden B und die Barcodes dürften unterschiedlich sein. Werde das Problem evtl. mit einem Art "Hauscode" abdecken, denke ich, aber das kommt später.


    Michael

    PS:

    Gibt es den evtl. ein Tipp zur Auslagerung der Connect Daten? Da man diese ja in anderen Projekten ggf. noch mal benötigt und nicht jedes mal manuell angeben muss. Da bis auf Datenbank und evtl. Tabelle sich ja nichts ändert.

    So hab den ersten Versuchscode dank Google zusammen. Dieser sieht wie folgt aus:


    Nur leider spuckt er lediglich folgende Fehlermeldung aus:

    Code
    Traceback (most recent call last):
      File "mysql.py", line 60, in <module>
        einlagern(scan)
      File "mysql.py", line 33, in einlagern
        cursor.execute("UPDATE warenlager SET menge=? WHERE barcode=?",(neuemenge, scan))
      File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 159, in execute
        query = query % db.literal(args)
    TypeError: not all arguments converted during string formatting


    Hoffe mein Gedankengang geht in die richtige Richtung. Den wenn ich das Einlagern hin bekommen habe, ist das auslagern ja eigentlich fast nur Copy Past. :bravo2:


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

    Einmal editiert, zuletzt von RaspiDo (23. Februar 2015 um 17:32)

  • Hallo


    noisefloor: Danke für den Code, nur mit MySQL funktioniert der Code so nicht.


    Schrieb ich oben auch. Was bei MySQL etwas anders ist:
    * Erzeugen der Tabelle - brauchst du aber nicht, weil du hast ja eine...
    * connection anlegen -> so wie in deinem Code
    * Platzhalter ? muss du durch was ersetzen, was MySQL unterstützt -> Doku lesen.

    Ich benutze kein MySQL (mehr), von daher muss den den Transfer von SQLite auf MySQL selber hin bekommen. Ist aber kein Hexenwerk! :)


    Aber zu dem anderen Code, wie bekomme ich 'cursor.fetchall()' in eine Variable? Normal wäre das ja 'a = cursor.fetchall()' oder?


    genau


    Nur wenn ich das richtig verstehe, wäre 'a' ja ein Array, Stimmt's?

    .
    Nein. Es ist ein `row-Object`, was sich wie eine Liste enthält.


    Wie bekomm ich das den im Detail dann hin? Weil normal Kann ich ja Array Elemente durch a[1] z.B. aufrufen. Oder verstehe ich da was falsch?


    Siehe mein Beispiel - da wird zuerst über das Ergebnis iteriert und dann noch das 3. Element der Liste ausgegeben.


    Den eine Ausgabe bekomme ich von 'cursor.fatchall()', sobald ich ein Print davor packe.


    Das macht man auch bestenfalls zum Testen und debuggen. Im späteren realen Programm greifst du direkt auf die Elemente zu, s.o.

    Gruß, noisefloor


  • Gibt es den evtl. ein Tipp zur Auslagerung der Connect Daten? Da man diese ja in anderen Projekten ggf. noch mal benötigt und nicht jedes mal manuell angeben muss. Da bis auf Datenbank und evtl. Tabelle sich ja nichts ändert.

    Der Import ähnlich wie mit php5 "include" sollte so möglich sein:

    Code
    def myconnect():
            global db
            db = MySQLdb.connect(user="user", passwd="geheim", db="gartensitzbank")
            return

    und speichern z.B. als db_connect.py. Zur Verbindung wie ein Modul importieren:

    Code
    import db_connect as db
    .
    .
    db.myconnect()

    und dann die Funktion aufrufen.

  • luetzel und bootsmann: Schade.

    Gibts den für den Updatebefehl eine Möglichkeit? Wie gesagt oben das Teil funktioniert ja nicht.

    Also wo ich erst per Select abfrage und dann möchte ich erst alten Wert + neue Ware addieren und per Update in die Tabelle eintragen. Nur es gibt wie oben beschrieben eine Fehlermeldung.


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

  • luetzel:

    Werde es mal ausprobieren mit dem was mir da hin geschrieben hast.

    Bin noch auf folgende Seite gestoßen:

    http://dev.mysql.com/doc/connector-…n-examples.html

    Gucke das mal durch. Nur Leute, das Forum hier ist echt Spitze. Man bekommt soweit möglich vernünftige Hilfe. Erlebt man nicht überall.


    Aus meiner Erfahrungen:

    War mal in einem anderem Forum gewesen und wenns da Antworten gab, waren die hochtrabend und mit Fachgedöns voll gepackt, so dass man als Hobbyprogrammierer nicht wirklich da hinter kommt, was gemeint ist. Weil ich z.B. nutze Programmierung dazu um Probleme für mich einfach zu Lösen und will da keine Dr. Arbeit draus machen.


    Daher noch mal :danke_ATDE:. Musste mal gesagt werden zwischendruch, auch wenn ich noch nich fertig bin :thumbs1:


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

    Einmal editiert, zuletzt von RaspiDo (26. Februar 2015 um 23:03)


  • luetzel:
    Werde es mal ausprobieren mit dem was mir da hin geschrieben hast.
    Bin noch auf folgende Seite gestoßen:
    http://dev.mysql.com/doc/connector-…n-examples.html
    Gucke das mal durch.

    Ok danke, das "python-mysql.connector" Modul existiert auch im Raspbian repo. Mir ist nur noch nicht ganz klar was der Unterschied zum MySQLdb Python-Modul sein soll, immerhin werden ja die gleichen Funktionen unterstützt.

    Wenn man die Verbindungsdaten in ein eigenes Skript auslagert, um es dann in einem anderen Skript zu verwenden, muss man das MySQL.connection Objekt trotzdem irgendwie übergeben. Alternativ könnte man die Verbindungsdaten einfach in einer Text-Datei ablegen, zeilenweise auslesen und wie in dem zitierten Beispiel in ein dictionary laden.

    Beste Grüße.

  • Hallo,

    RaspiDo: wo bekommt man den in der MySQL-Doku beschriebenen Connector eigentlich her? Ist der bei der Installation von MySQL ootb dabei?

    Die beiden Module, die ich kenne, um von Python aus auf eine MySQL-DB zuzugreifen sind:

    * MySQLdb http://mysql-python.sourceforge.net/: viel genutzt, hat aber ein paar "Macken", z.B. unvollständige Umsetzung der in der Python DB-API 2.0 beschriebenen Platzhalter (hatten wir oben ja schon ;)
    * PyMySQL https://github.com/PyMySQL/PyMySQL: neuer als MySQLdb und komplett in Python umgesetzt.

    Ich für meinen Teil hahe früher (damals halt... ;) auch MySQL benutzt, benutzte aber schon länger nur noch SQLite, was das (für mich) für die allermeisten Fälle völlig ausreichend ist. Oder CouchDB - aber das ist ja kein RDBMS ;)

    Gruß, noisefloor

  • noisefloor: Ich nutze ja MySQL weil ich das extern nutze und daher KEINE Ress Belastung habe. Und zum Anderen ich evtl. noch eine Abfrage nutzen möchte, wo ich es auf einer einfachen Homepage oder als Email Inhalt weiter nutzen kann.

    Aber werde die beiden Links noch mal nachgucken. Gerade komme ich noch nicht dran es zu testen.


    Michael

    Der Raspberry Pi ist schon ein schönes Spielzeug mit dem man einiges anfangen kann.

    :angel: :wallbash:

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!