Anzeige:
Ergebnis 1 bis 7 von 7

Thema: Fragen zu Python und Mysql

  1. #1
    Registrierter Benutzer Avatar von michel_vaclav
    Registriert seit
    Jan 2003
    Ort
    daheim
    Beiträge
    1.055

    Fragen zu Python und Mysql

    Hallo zusammen,

    da ich in mrunix.de keinerlei Anworte erhalte, probiere ich es hier nochmal und führe, sofern es ein längerer Thread wird, diesen hier weiter.

    Ich habe da ein paar Erklärungsbedürfnisse zum Umgang mit Variablen in Python bzw. das Verarbeiten in Mysql.

    Ich lese Daten aus einem Textfile ein:
    Code:
    with open(/pfad/zur/datei) as file:
        for _ in range(53):
            file.readline()
        daten = '%.1f' % float(file.readline()[6:])
        file.close()
    Die relevanten Daten sind in Zeile 53 der Datei zu finden.

    Frage 1: Welchen Typ hat nun die Variable "daten"?

    Wenn der Wert eine bestimmte Grenze überschreitet, ist er unplausibel und ich möchte "NULL" in die Datenbank schreiben. Dazu prüfe ich:
    Code:
        if daten > grenze:
            daten = None
    Frage 2: Wenn nun diese Bedingung erfüllt wird und daten auf "None" gesetzt wird, von welchem Typ ist dann "daten"?

    Nun möchte ich den ausgelesenen Wert in eine mysql-Datenbank schreiben.
    Dazu verwende ich:
    Code:
    cursor = db_connection.cursor()
    cursor.execute(
        """insert into datenbank set daten='%s'  ON DUPLICATE KEY UPDATE daten='%s''""", float(daten))
    (Der Code ist unvollständig und möglicherweise funktioniert es so auch nicht, aber es geht mir um das prinipielle Verständnis beim Einfügen.

    Fall 1: Meine Daten waren plausibel, also nicht leer, dann muss ich in die Spalte der Datenbank ein Float einfügen, was ich mit float(daten) erreiche.

    Frage 3: Was hat es mit dem '%s' auf sich?
    Frage 4: Was ist der Unterschied zu %s, also ohne die Hochkommata?

    Fall 2: Waren die eingelesenen Werte unplausibel, so ist ja jetzt die Variable daten leer. Jetzt funktioniert mein "insert" nicht mehr, die Fehlermeldung:
    Code:
    TypeError: float() argument must be a string or a number, not 'NoneType'
    sagt mir, dass ich hier einen Typenkonflikt habe.

    Wie macht man das richtig?
    Danke für Erläuterungen

    michel_vaclav
    Visit me at fehrmich.spdns.de

  2. #2
    Premium Mitglied Avatar von spychodelics
    Registriert seit
    Nov 2002
    Ort
    Offenbach
    Beiträge
    623
    Moin,

    also meines Wissens nach (und das ist was Python angeht ziemlich dürftig, da gerade damit angefangen) kannst du da hinten kein float übergeben sondern sollst lediglich den variablennamen angeben, mysqldb bastelt sich das selbst zurecht.

    hier mal was ich letzten donnerstag zu uebungszwecken zusammengebaut habe:

    Code:
    import MySQLdb
    import sys
    #import pysnooper
    
    #@pysnooper.snoop('/tmp/pyfile.log')
    
    
    class Menu:
        '''Zeige ein Menü und reagiere auf Auswahl wenn ausgeführt'''
    
        __host       = None
        __user       = None
        __password   = None
        __database   = None
    
        def __init__(self, host='localhost', user='user', password='password', database='dbname'):
            self.__host     = host
            self.__user     = user
            self.__password = password
            self.__database = database
            self.db = MySQLdb.connect(self.__host, self.__user, self.__password, self.__database)
            self.dbpointer = self.db.cursor()
            self.auswahl ={
            "1": self.login,
            "2": self.add,
            "3": self.modify_user,
            "4": self.delete_user,
            "5": self.quit
            }
    
        def __del__(self):
            self.db.close()
            print("DB Erfolgreich geschlossen")
    
        def display_menu(self):
            print("""
    Hauptmenü:
    
    1: Benutzer Login
    2: Benutzer hinzufügen
    3: Benutzer Passwort ändern
    4: Benutzer löschen
    5: Programm beenden
    """)
    
        def run(self):
            '''Zeige ein Menü und reagiere auf Auswahl wenn ausgeführt'''
            while True:
                self.display_menu()
                wahl = input("Ihre Wahl: ")
                action = self.auswahl.get(wahl)
                if action:
                    action()
                else:
                    print("{0} is not a valid choice".format(wahl))
    
        def login(self):
            print("Bitte geben Sie Ihre Logindaten ein")
            username = input("Username: ")
            password = input("Password: ")
            self.dbpointer.execute("""SELECT * FROM admins WHERE username = %s AND password = %s""", (username, password, ))
            print(self.dbpointer._last_executed)
            result = self.dbpointer.fetchone()
            if result:
                print("Willkommen, " + result[1])
            else:
                print("Keine Übereinstimmung!")
    
        def add(self):
            print("Wie soll der neue User heißen?")
            username = input("Username: ")
            password = input("Password: ")
            self.dbpointer.execute("""SELECT * FROM admins WHERE username = %s""", (username, ))
            result = self.dbpointer.fetchone()
            if result and username in result:
                print(username + "Ist bereits vorhanden! Bitte wählen Sie einen anderen Namen")
            else:
                #sql = INSERT INTO `admins` (`username`, `password`) VALUES (username, password)
                self.dbpointer.execute("""INSERT INTO admins (username, password) VALUES (%s, %s)""", (username, password, ))
                self.db.commit()
                print(self.dbpointer._last_executed)
                print("User wurde hinzugeuegt")
    
        def modify_user(self):
            print("Noch kein Inhalt!")
    
        def delete_user(self):
            print("Noch kein Inhalt!")
    
    
        def quit(self):
            print("Danke fürs vorbeischauen heute!")
            sys.exit("Gude!")
    
    if __name__ == "__main__":
        Menu().run()


    https://mysqlclient.readthedocs.io/u...e.html#mysqldb

    hier steht auch noch so einiges was man halt verstehen muss, tuple, sql literal value etc.

  3. #3
    Registrierter Benutzer
    Registriert seit
    Apr 2009
    Ort
    Erde
    Beiträge
    2.814
    Python ist anders, du musst jedesmal die Typen prüfen. Python gibt dir dazu zwei Methoden an die Hand, type bzw. isinstance

    https://docs.python.org/3/library/functions.html#type
    https://docs.python.org/3/library/fu...tml#isinstance

    Die erste verwendet man idR mit dem is Operator == geht aber auch - sa https://docs.python.org/3/library/st...ml#comparisons. Die zweite ist allerdings zu bevorzugen, wegen Vererbung, außerdem sind auch mehrere Typangaben möglich.
    Demo: https://onlinegdb.com/rJ-AuHhMS

    Fazit:
    Du kannst dich nicht drauf verlassen, dass der Typ bleibt, du musst vorjedem Zugriff sicherstellen, dass der Typ noch passt.

    [edit]Kleiner Korrukturen bzgl. type vs isinstance
    Geändert von nopes (29.07.19 um 16:34 Uhr) Grund: fixes
    Gruß nopes
    (,,,)---(^.^)---(,,,) /var/log/messages | grep cat

  4. #4
    Registrierter Benutzer Avatar von snowcrash23
    Registriert seit
    Jun 2006
    Ort
    Unbekannt Verzogen
    Beiträge
    577
    Zitat Zitat von michel_vaclav Beitrag anzeigen
    Frage 3: Was hat es mit dem '%s' auf sich?
    Frage 4: Was ist der Unterschied zu %s, also ohne die Hochkommata?
    Das ist ein Platzhalter, er kommt nur innerhalb von strings und somit auch immer innerhalb von Hochkomma oder Anführungszeichen vor. Kann auch im "moderneren" format-Stil durch {} ersetzt werden. Siehe Basic formatting.

    Wie macht man das richtig?
    Wenn ich richtig verstehe möchtest du auch NULL in die Datenbank schrieben:
    Code:
    daten = float(daten)
    if daten > grenze:
        daten = None
    
    cursor.execute("INSERT INTO datenbank_tabelle (tabellen_spalte) VALUES(?)", (daten,))
    Bei SQL am besten nicht Pythons String-Formatierung, sondern lieber Prepared Statements/Parameterized Queries benutzen.
    Warum? Ein Beispiel das für SQL-Injections anfällig ist wurde hier bereits gepostet. Ein Login mit beliebigem Namen und dem Passwort "vollkommen_egal OR 1" würde in spychodelics code aus Post #2 reichen um sich als ersten Benutzer der in der Datenbank gefunden wird anzumelden, mit Sicherheit nicht das was gewollt ist.

    MfG
    snowcrash23
    Geändert von snowcrash23 (29.07.19 um 14:47 Uhr)
    OS:Arch LinuxCPU:Core i5-2500K
    MB:P8P67PRORAM:16GB DDR3GK:NV GTX570

    Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

  5. #5
    Registrierter Benutzer
    Registriert seit
    Apr 2009
    Ort
    Erde
    Beiträge
    2.814
    Ja die bösen Strings, nur so als Übung selber bauen macht aber schon Sinn, Testen dabei nicht vergessen und man ist bereit richtig robustes Zeugt zu erstellen. Demo: https://onlinegdb.com/BJwPAKJQH
    Immer wieder erstaunlich, wie gut man sowas mit Python runter hacken kann und was man dabei lernt

    [edit]
    Du brauchst allerdings eher eine Klasse, die dir Irgendwas in Float umbaut und da ich nicht weiß, wie lang der Code dort lebt - eine Klasse die "Irgendwas" in Text umbaut inklusive Tests:
    Code:
    import unittest
    class my_sql_text_test(unittest.TestCase):
        '''
        test class 
          - I want to be able to use text, numbers and none as text in sql statements
          - I want to be able to seperate types
        '''
        class some_type:
            '''
            just a helper class to test the type limitation of the my_sql_text class
            '''
            def __init__(self, data):
                self.data = data
                
        def test_prepare(self):
            for val in (self.some_type('bla'), complex(1, 2)):
                with self.assertRaises(TypeError):
                    my_sql_text.prepare(val)
            self.assertEqual(my_sql_text.prepare(""), "''")
            self.assertEqual(my_sql_text.prepare("'"), "''''")
            self.assertEqual(my_sql_text.prepare("''"), "''''''")
            self.assertEqual(my_sql_text.prepare(''), "''")
            self.assertEqual(my_sql_text.prepare(-1), "'-1'")
            self.assertEqual(my_sql_text.prepare(1), "'1'")
            self.assertEqual(my_sql_text.prepare(1.2), "'1.2'")
            self.assertEqual(my_sql_text.prepare(None), "NULL")
            
        def test_internals(self):
            '''
            NOTE: I want 100% code coverage and there are no private
                  members in python 
                  I therefore also need to test private functions
                  
                  I have already tested the "good" pathes of private
                  member functions 
                  -> all I need to test are the type limitations
                  (to proof I should turn on code coverage; it have to be 100%)
            '''
            for function in (my_sql_text._none, my_sql_text._number, my_sql_text._str):
                for val in (self.some_type('bla'), complex(1, 2)):
                    with self.assertRaises(TypeError):
                        function(val)
    
    class my_sql_text:
        '''
        A simple (static) class to prepare any int, float or str value 
        to be used as text which can be used with any sql statement
        NOTE: if a member name starts with _, it is considered to be private 
              sa https://docs.python.org/3/tutorial/classes.html
        '''
        def prepare(val):
            if isinstance(val, (float, int)):
                return my_sql_text._number(val)
            if isinstance(val, type(None)):
                return my_sql_text._none(val)
            if isinstance(val, str):
                return my_sql_text._str(val)
            raise TypeError("input type must be float, int, NoneType or str")
                
        def _none(val):
            if not isinstance(val, type(None)):
                raise TypeError("input type must be NoneType")
            return "NULL"
            
        def _number(val): 
            if not isinstance(val, (float, int)):
                raise TypeError("input type must be float or int")
            return "'{}'".format(val)
        
        def _str(val):
            if not isinstance(val, str):
                raise TypeError("input type must be str")
            return "'{}'".format(val.replace("'", "''"))
    
    
    test = False # set to True to run tests in the my_sql_text_test class
    if test:
        unittest.main()
        
    sql = "INSERT INTO tbl_foo (col_bar) VALUES"
    s = "\n  "
    for val in (0, 1.2, "3.45°", '6.789s', None, "';SELECT 1;--"):
        sql += "{}({})".format(s, my_sql_text.prepare(val))
        s = "\n ,"
    sql += "\n;"
    print(sql)
    Geändert von nopes (01.08.19 um 00:00 Uhr) Grund: code update; benutzt jetzt format; siehe #4; "test 1st"
    Gruß nopes
    (,,,)---(^.^)---(,,,) /var/log/messages | grep cat

  6. #6
    Registrierter Benutzer Avatar von snowcrash23
    Registriert seit
    Jun 2006
    Ort
    Unbekannt Verzogen
    Beiträge
    577
    Offtopic:
    @nopes Nunja... ich glaube ja das weder der TE noch irgendjemand sonst etwas mit dieser "Klasse" anfangen kann. Darf ich fragen ob dass das erste mal ist das du Python programmierst?
    Jeder Aufruf von sql_text.prepare() in deinem Code kann durch ein einfaches str() ersetzt werden und deine Tests laufen durch... Die Klasse ist somit vollkommen überflüssig (https://www.onlinegdb.com/rkayOCazS).

    MfG
    snowcrash23
    OS:Arch LinuxCPU:Core i5-2500K
    MB:P8P67PRORAM:16GB DDR3GK:NV GTX570

    Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn

  7. #7
    Registrierter Benutzer
    Registriert seit
    Apr 2009
    Ort
    Erde
    Beiträge
    2.814
    Nein ich Programmiere nicht mehr oft mit Python, leider
    Das die Klasse nichts macht ist quatsch, sie ist nicht überflüssig und prepare kann man nicht einfach durch str() ersetzen
    Code:
    ,('';SELECT 1;--')    /* au */            
    vs          
    ,(''';SELECT 1;--')  /* ok */
    und
    ,('None') /* au, man könnte über ('') diskutieren */
    vs
    ,(NULL) /* ok */
    [edit]
    Ich war mal so frei und habe die letzten Reste meiner Klassen eliminiert, keine Klasse, keine internals, die Tests gehen trotzdem schief, weil str() halt alles frist: https://onlinegdb.com/ry4kXgCGr
    Geändert von nopes (30.07.19 um 18:43 Uhr)
    Gruß nopes
    (,,,)---(^.^)---(,,,) /var/log/messages | grep cat

Ähnliche Themen

  1. SUCHE: fuse python bindings für python 2.4 und Suse 10
    Von skurial im Forum System installieren und konfigurieren
    Antworten: 4
    Letzter Beitrag: 20.11.05, 17:21
  2. [python] "init failed" - ein problem mit mysql
    Von OpOs im Forum Linux Allgemein
    Antworten: 3
    Letzter Beitrag: 18.10.05, 21:04
  3. MYSQL -> ein paar grundlegende fragen...
    Von jean_luc_picard im Forum Linux als Server
    Antworten: 17
    Letzter Beitrag: 01.10.02, 21:15
  4. Allgemeine Fragen zur MySQL Installation
    Von Hifi im Forum Linux als Server
    Antworten: 1
    Letzter Beitrag: 11.08.02, 22:57
  5. ´ma kurz fragen : mysql
    Von michael.sprick im Forum Linux als Server
    Antworten: 1
    Letzter Beitrag: 20.06.02, 14:22

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •