Fehlermeldung TypeError: can only concatenate str (not "list") to str

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
till
User
Beiträge: 3
Registriert: Dienstag 30. Juni 2020, 14:59

Hallo
Nach langer Suche habe ich noch keine Passene Lösung für mein Problem gefunden und hoffe, dass mir hier jemand helfen kann.
Ich möchte für ein Projekt RFID-Karten beschreiben und auslesen und die ausgelesenen Daten in eine MySQL-Datenbank speichern.
Das Beschreiben und Auslesen funktioniert ohne Probleme, aber ich bekomme beim eintragen in die Datenbank eine Fehlermeldung.
Wenn ich statt den ausgelesenen Werten selber Werte angebe, funktioniert die Eintragung in die Datenbank.

Fehlermeldung

Code: Alles auswählen

Traceback (most recent call last):
  File "Pfad zur Datei/mysql_test3.py", line 111, in <module>
    sql = "INSERT INTO RFID_Chips (nummer, uid, name_ascii, name) VALUES ("+nummer+", "+str(uid[0])+str(uid[1])+str(uid[2])+str(uid[3])+", "+MIFAREReader.MFRC522_Read(8)+", "+name+")"
TypeError: can only concatenate str (not "list") to str
hier ist der Code

Code: Alles auswählen

import mysql.connector
import RPi.GPIO as GPIO
import MFRC522
import signal


GPIO.setwarnings(False)

mydb = mysql.connector.connect(
  host="localhost",
  user="username",
  password="password",
  database="database"
)

print(mydb)

nummer=input("Gib eine Nummer ein: ")
name=input("Gib einen Kartennamen ein: ")
if len(name)>16:
 name=name[:16]
data = [ord(x) for x in list(name)]

continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print ("Ctrl+C captured, ending read.")
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
    
    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
    if status == MIFAREReader.MI_OK:
        print ("Card detected")
    
    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        print ("Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3]))
    
        # This is the default key for authentication
        key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
        
        # Select the scanned tag
        MIFAREReader.MFRC522_SelectTag(uid)

        # Authenticate
        status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
        print ("\n")

        # Check if authenticated
        if status == MIFAREReader.MI_OK:

            # Variable for the data to write
            #data = []

            # Fill the data with 0xFF
            for x in range(0,16):
                data.append(0xFF)

            print ("Sector 8 looked like this:")
            # Read block 8
            print (MIFAREReader.MFRC522_Read(8))
            print ("\n")

            print ("Sector 8 will now be filled with 0xFF:")
            # Write the data
            print (MIFAREReader.MFRC522_Write(8, data))
            print ("\n")

            print ("It now looks like this:")
            # Check to see if it was written
            print (MIFAREReader.MFRC522_Read(8))
            print ("\n")

            #data = []
            # Fill the data with 0x00
            for x in range(0,16):
                data.append(0x00)

            print ("Now we fill it with 0x00:")
            print (MIFAREReader.MFRC522_Write(8, data))
            print ("\n")

            print ("It is now empty:")
            # Check to see if it was written
            print (MIFAREReader.MFRC522_Read(8))
            print ("\n")

            # Insert in DB
            mycursor = mydb.cursor()

            
            sql = "INSERT INTO RFID_Chips (nummer, uid, name_ascii, name) VALUES ("+nummer+", "+str(uid[0])+str(uid[1])+str(uid[2])+str(uid[3])+", "+MIFAREReader.MFRC522_Read(8)+", "+name+")"
            
            print(sql+"\n")

            mycursor.execute(sql)

            mydb.commit()
            
            print(mycursor.rowcount, "record inserted.")
                   
            # Stop
            MIFAREReader.MFRC522_StopCrypto1()

            # Make sure to stop reading for cards
            continue_reading = False

        else:
            print ("Authentication error")

Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@till: Man bastelt keine Werte in SQL mit Zeichenkettenoperationen. Dafür gibt es Platzhalter und das zweite Argument von `execute()`.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
till
User
Beiträge: 3
Registriert: Dienstag 30. Juni 2020, 14:59

@_blackjack_

Ich habe die Stelle im Code geändert und bekomme jetzt eine andere Fehlermeldung.


geänderter Code

Code: Alles auswählen

            # Insert in DB
            mycursor = mydb.cursor()

            sql = "INSERT INTO RFID_Chips (nummer, uid, name_ascii, name) VALUES (%s, %s, %s, %s)"
            val = (nummer, str(uid[0])+str(uid[1])+str(uid[2])+str(uid[3]), MIFAREReader.MFRC522_Read(8), name)
            
            mycursor.execute(sql, val)

            mydb.commit()

Fehlermeldung

Code: Alles auswählen

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/mysql/connector/conversion.py", line 183, in to_mysql
    return getattr(self, "_{0}_to_mysql".format(type_name))(value)
AttributeError: 'MySQLConverter' object has no attribute '_list_to_mysql'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/mysql/connector/cursor.py", line 432, in _process_params
    res = [to_mysql(i) for i in res]
  File "/usr/local/lib/python3.7/dist-packages/mysql/connector/cursor.py", line 432, in <listcomp>
    res = [to_mysql(i) for i in res]
  File "/usr/local/lib/python3.7/dist-packages/mysql/connector/conversion.py", line 186, in to_mysql
    "MySQL type".format(type_name))
TypeError: Python 'list' cannot be converted to a MySQL type

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/Alarmanlage/mysql_test3.py", line 115, in <module>
    mycursor.execute(sql, val)
  File "/usr/local/lib/python3.7/dist-packages/mysql/connector/cursor.py", line 557, in execute
    psub = _ParamSubstitutor(self._process_params(params))
  File "/usr/local/lib/python3.7/dist-packages/mysql/connector/cursor.py", line 437, in _process_params
    "Failed processing format-parameters; %s" % err)
mysql.connector.errors.ProgrammingError: Failed processing format-parameters; Python 'list' cannot be converted to a MySQL type
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

`as` bei Import ist zum Umbenennen da, GPIO wird aber gar nicht umbenannt.
Warnungen sind dazu da, dass sie behoben werden, nicht dass sie ignoriert werden. Dazu muß aber cleanup verlässlich aufgerufen werden, in einem finally-Block.
Kein ausführbarer Code sollte auf oberster Ebene stehen, sondern alles in Funktionen.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 1 und mal 4.
Man sollte keine globalen Variablen benutzen, die Methode über SIGINT ist dabei besonders kompliziert und fehleranfällig, da man auch simplest KeyboardInterrupt abfangen könnte.
Die Statusmeldungen sollte man nicht nur ausgeben, sondern auch berücksichtigen, Wenn Status nicht MI_OK ist, sollte man mit dem Lesen auch nicht weitermachen.
`data` wird immer nur mit append vergrößert, und nie gelehrt.
`MFRC522_Read` liefert eine Liste, die kann man natürlich nicht so in die Datenbank schreiben.
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ergänzend: ``str(uid[0])+str(uid[1])+str(uid[2])+str(uid[3])`` ist kaputt weil das mehr als eine ID auf die gleiche Zeichenkette abbilden kann.

Da vieles von dem Code aus Beispielen aus dem Netz ist, bleibt mal wieder als Fazit, dass da draussen eine ganze Menge Mist zu finden ist. ☹️
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Ungetestet:

Code: Alles auswählen

import mysql.connector
from RPi import GPIO
import MFRC522

def connect_to_database():
    return mysql.connector.connect(
        host="localhost",
        user="username",
        password="password",
        database="database"
    )

def input_card_name():
    nummer = input("Gib eine Nummer ein: ")
    name=input("Gib einen Kartennamen ein: ")
    name = name[:16]
    data = [ord(x) for x in name]
    return nummer, data

def uid_to_str(uid):
    return ''.join(':02x' % c for c in uid)
    
def process(database, nummer, data, mifa_reader):
    # Scan for cards    
    (status,TagType) = mifa_reader.MFRC522_Request(mifa_reader.PICC_REQIDL)

    if status != mifa_reader.MI_OK:
        # If a card is not found
        return False
    print("Card detected")
    
    # Get the UID of the card
    status, uid = mifa_reader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status != mifa_reader.MI_OK:
        return False
        
    # Print UID
    print("Card read UID: %s" % uid_to_str(uid))
    
    # This is the default key for authentication
    key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
        
    # Select the scanned tag
    mifa_reader.MFRC522_SelectTag(uid)

    # Authenticate
    status = mifa_reader.MFRC522_Auth(mifa_reader.PICC_AUTHENT1A, 8, key, uid)

    # Check if authenticated
    if status != mifa_reader.MI_OK:
        print("Authentication error")
        return False

    # Variable for the data to write
    # data = []

    # Fill the data with 0xFF
    data.extend([0xFF] * 16)

    print("Sector 8 looked like this:", mifa_reader.MFRC522_Read(8))
    print("Sector 8 will now be filled with 0xFF:", mifa_reader.MFRC522_Write(8, data))
    print("It now looks like this:", mifa_reader.MFRC522_Read(8))
    #data = []
    # Fill the data with 0x00
    data.extend([0] * 16)
    print("Now we fill it with 0x00:", mifa_reader.MFRC522_Write(8, data))
    print("It is now empty:", mifa_reader.MFRC522_Read(8))

    card_data = mifa_reader.MFRC522_Read(8)

    cursor = database.cursor()
    sql = "INSERT INTO RFID_Chips (nummer, uid, name_ascii, name) VALUES (%s, %s, %s, %s)"
    cursor.execute(sql, [nummer, uid_to_str(uid), uid_to_str(card_data), name])
    print(cursor.rowcount, "record inserted.")
    database.commit()
    mifa_reader.MFRC522_StopCrypto1()
    return True

    
def main():
    try:
        database = connect_to_database()
        nummer, data = input_card_name()
        mifa_reader = MFRC522.MFRC522()
        while not process(database, nummer, data, mifa_reader):
            pass
    except KeyboardInterrupt:
        print("Ctrl+C captured, ending read.")
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
Die data-Behandlung sieht für mich total kaputt aus.
till
User
Beiträge: 3
Registriert: Dienstag 30. Juni 2020, 14:59

Nach zwei änderungen hat der Code funktioniert.

Hier noch einmal der Code:

Code: Alles auswählen

import mysql.connector
from RPi import GPIO
import MFRC522

def connect_to_database():
    return mysql.connector.connect(
        host="localhost",
        user="username",
        password="password",
        database="database"
    )

def input_card_name():
    nummer = input("Gib eine Nummer ein: ")
    name = input("Gib einen Kartennamen ein: ")
    name = name[:16]
    data = [ord(x) for x in name]
    return nummer, data, name

def uid_to_str(uid):
    return ''.join('{:02x}'.format(c) for c in uid)
    
def process(database, nummer, data, mifa_reader, name):
    # Scan for cards    
    (status,TagType) = mifa_reader.MFRC522_Request(mifa_reader.PICC_REQIDL)

    if status != mifa_reader.MI_OK:
        # If a card is not found
        return False
    print("Card detected")
    
    # Get the UID of the card
    status, uid = mifa_reader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status != mifa_reader.MI_OK:
        return False
        
    # Print UID
    print("Card read UID: %s" % uid_to_str(uid))
    
    # This is the default key for authentication
    key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
        
    # Select the scanned tag
    mifa_reader.MFRC522_SelectTag(uid)

    # Authenticate
    status = mifa_reader.MFRC522_Auth(mifa_reader.PICC_AUTHENT1A, 8, key, uid)

    # Check if authenticated
    if status != mifa_reader.MI_OK:
        print("Authentication error")
        return False

    # Variable for the data to write
    # data = []

    # Fill the data with 0xFF
    data.extend([0xFF] * 16)

    print("Sector 8 looked like this:", mifa_reader.MFRC522_Read(8))
    print("Sector 8 will now be filled with 0xFF:", mifa_reader.MFRC522_Write(8, data))
    print("It now looks like this:", mifa_reader.MFRC522_Read(8))
    #data = []
    # Fill the data with 0x00
    data.extend([0] * 16)
    print("Now we fill it with 0x00:", mifa_reader.MFRC522_Write(8, data))
    print("It is now empty:", mifa_reader.MFRC522_Read(8))

    card_data = mifa_reader.MFRC522_Read(8)

    cursor = database.cursor()
    sql = "INSERT INTO RFID_Chips (nummer, uid, name_ascii, name) VALUES (%s, %s, %s, %s)"
    cursor.execute(sql, [nummer, uid_to_str(uid), uid_to_str(card_data), name])
    print(cursor.rowcount, "record inserted.")
    database.commit()
    mifa_reader.MFRC522_StopCrypto1()
    return True

    
def main():
    try:
        database = connect_to_database()
        nummer, data, name = input_card_name()
        mifa_reader = MFRC522.MFRC522()
        while not process(database, nummer, data, mifa_reader, name):
            pass
    except KeyboardInterrupt:
        print("Ctrl+C captured, ending read.")
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()

Ich bedanke mich für eure Hilfe
Antworten