Fehlermeldung

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Guten Morgen, Ich hoffe ihr hattet alle ein erholsames Wochenende.

Ich versuche gerade ein Login zu basteln bekomme aber eine Fehlermeldung die für mich keinen Sinn ergibt.

Code: Alles auswählen

Label(nb, text="Username", font="Helvetica 13 bold").grid(row=4, column=0, pady=5, padx=5)
Label(nb, text="Passwort", font="Helvetica 13 bold").grid(row=4, column=1, pady=5, padx=5)

passwort = Entry(nb, font=10)
passwort.grid(row=3, column=1, padx=5, pady=5)

benutzername = Entry(nb, font=10)
benutzername.grid(row=3, column=0, padx=5, pady=5)

def login():
    test = benutzername.get()

    connection = psycopg2.connect("dbname=sqltest")
    cursor = connection.cursor()
    cursor.execute('SELECT * FROM mitarbeiter WHERE loginname = %s ' % benutzername.get())

    for dsatz in (cursor):
        uname    =   dsatz[0]
        pw       =   dsatz[1]
    print(uname, pw)

Button(nb, text = "Login", command = login).grid(row=5, column=0, sticky=NSEW, pady=4)
Simpler Aufbau für das Login, bei der stelle execute komm folgende Meldung aber auch nur wenn ich die Zeile so schreibe wie gerade:

Code: Alles auswählen

  File "/home/gast/Arbeitsfläche/Projekte/Datenbank/login.py", line 41, in login
    cursor.execute('SELECT * FROM mitarbeiter WHERE loginname = %s ' % benutzername.get())
psycopg2.ProgrammingError: FEHLER:  Spalte »mustermann« existiert nicht
LINE 1: SELECT * FROM mitarbeiter WHERE loginname = mustermann 
Ändere ich das ganze ab und schreib es so

Code: Alles auswählen

Label(nb, text="Username", font="Helvetica 13 bold").grid(row=4, column=0, pady=5, padx=5)
Label(nb, text="Passwort", font="Helvetica 13 bold").grid(row=4, column=1, pady=5, padx=5)

passwort = Entry(nb, font=10)
passwort.grid(row=3, column=1, padx=5, pady=5)

benutzername = Entry(nb, font=10)
benutzername.grid(row=3, column=0, padx=5, pady=5)

def login():
    test = benutzername.get()

    connection = psycopg2.connect("dbname=sqltest")
    cursor = connection.cursor()
    cursor.execute('SELECT * FROM mitarbeiter WHERE loginname = %s ' , benutzername.get())         <---------- Komma statt %

    for dsatz in (cursor):
        uname    =   dsatz[0]
        pw       =   dsatz[1]
    print(uname, pw)

Button(nb, text = "Login", command = login).grid(row=5, column=0, sticky=NSEW, pady=4)
Kommt diese Meldung:

Code: Alles auswählen

  File "/home/gast/Arbeitsfläche/Projekte/Datenbank/login.py", line 41, in login
    cursor.execute('SELECT * FROM mitarbeiter WHERE loginname = %s ', benutzername.get())
TypeError: not all arguments converted during string formatting
Letztere Variante nutze ich bei einer Suchfunktion die komischerweise ohne Probleme funktioniert und hier bekomm ich Fehler.

Bei der ersten Variante is es ja ganz kurios wie man aus der Fehlermeldung erkennen kann.
Wenn Ich im Eingabefeld den gewünschten Namen suche kommt der Fehler das die Spalte mit dem Namen nicht existiert.
Gebe ich aber den Spaltennamen!!! ein bekomm ich die Datensätze????
BlackJack

@Kalli87: Genau wie in Python gibt es in SQL einen Unterschied zwischen literalen Zeichenketten und Namen. In Deinem ersten Beispiel suchst Du nicht nach dem *Wert* 'mustermann' in der Spalte `loginname`, sondern alle Datensätze bei denen die Werte in den Spalten `loginname` und `mustermann` gleich sind. Nur hat Deine Tabelle keine Spalte mit dem Namen `mustermann`. Deshalb die Ausnahme. Das Problem anhand von Python-Code demonstriert:

Code: Alles auswählen

In [1]: print peter
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-063369a130d4> in <module>()
----> 1 print peter

NameError: name 'peter' is not defined

In [2]: print 'peter'
peter
Beim zweiten Beispiel, also ohne wie ``%`` wie es sich gehört, gibst Du bei einer Eingabe von 'mustermann' 10 Werte an, von denen aber nur der erste für den Platzhalter eingesetzt wird, und die restlichen 9 sind zu viel, deshalb die Ausnahme. Warum 10? Nun weil als zweites Argument bei dem `execute()`-Aufruf eine *Sequenz* von Werten erwartet wird und Du da eine Zeichenkette übergibst. Zeichenketten sind Sequenzen von Buchstaben und 'mustermann' hat 10 davon. Wenn Du die Zeichenkette als *einen* Wert betrachten willst, dann musst Du die als einziges Element in einen Sequenztyp stecken und den übergeben. Also zum Beispiel ein Tupel oder eine Liste.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Ah ok ich merk auch gerade das bei meiner Suchfunktion das gleiche Problem entsteht wenn
ich nach einer 2 Stelligen Zahl suche. Is natürlich leicht bescheiden.....

Aber danke für den Hinweis :)
Hab es geändert und nun funktioniert es richtig
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Ich bins wieder :)

Code: Alles auswählen

user=[]
pw=[]
def login():

    user.append(benutzername.get())
    pw.append(passwort.get())

    connection = psycopg2.connect("dbname=sqltest")
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM mitarbeiter WHERE loginname = %s", user)

    for dsatz in (cursor):
        uname    =   dsatz[0]

        connection = psycopg2.connect("dbname=sqltest")
        cursor = connection.cursor()
        cursor.execute("SELECT * FROM mitarbeiter WHERE passwort = %s", pw)

        for dsatz in (cursor):
            passw    =   dsatz[1]

            print(pw, passw)
            print(user, uname)

    if pw == passw and user == uname:
        print("funktioniert")
    else:
        print("funktioniert nicht")
Ausgabe wäre:

Code: Alles auswählen

['123456'] 123456
['mustermann'] mustermann
funktioniert nicht
Mein Frage wäre jetzt:
Bei der Ausgabe erkennt man ja schon das die pw und passw nicht wirklich gleich sind und das gleiche gilt auch für den user.
Ich hab es schon mit replace versucht aber man darf in einer liste ja kein replace nutzen.
Gibt es eine Möglichkeit das ganze so anzupassen das sie wirklich gleich sind?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Deine Funktion macht zu viele Dinge und die Dinge die sie macht sind auch nicht schön. Beispielsweise sollte die Funktion login den Usernamen und das Passwort als Parameter übergeben bekommen und dann nur zurückgeben, ob die Authentifizierung geklappt hat. Die Datenbankverbindung sollte man auch besser noch als Parameter von außen hineingeben.

Warum baust du eine Liste für user und pw und warum sind das globale Werte?
Warum heißt pw überhaupt unnötig abgekürzt pw und nicht password?
Warum machst du zwei Verbindungen zur Datenbank auf?
Warum fragst du Dinge die eine UND-Verknüpfung haben in zwei verschiedenen Queries ab?

Im Prinzip beschränkt sich die Abfrage doch auf Folgendes:

Code: Alles auswählen

cursor.execute("SELECT * FROM mitarbeiter WHERE loginname = %s AND passwort = %s", (user, password))
Bekommst du ein Ergebnis dann ist der User authentifiziert, bekommst du keins, dann nicht.

Grundsätzlich sollte dir auch noch klar sein, dass man aus Sicherheitsgründen Passwörter nie im Klartext sondern immer nur als Hash-Value abspeichert.
BlackJack

Ergänzend: Beim Hashwert vorzugsweise einer der durch eine für Passworte geeignete Hashfunktion berechnet wurde und nicht etwas wie MD5. Und auch nicht direkt das Passwort sondern mit einem „salt”. Am besten schreibt man das nicht selbst, sondern verwendet eine vorhandene Bibliothek. `pbkdf2`, `bcrypt`, oder `passlib` beispielsweise.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@/me danke für deine antwort und kritik

Um deine Fragen mal zu beantworten.

1. Wie man weiter oben aus diesem Thread erlesen kann hatte ich das Problem das es Probleme gab mit der ich nenne es mal "Formatierung" (String converting oder was auch immer los war)
Das ließ sich halt nur beheben wenn ich das das ganze in eine liste speicher damit die komplette Eingabe auch genommen werden konnte damit das mit der Datenbankabfrage funktioniert.
Sonst nahm er nur den ersten Buchstaben aus der Eingabe der Rest wurde ignoriert, was ja nicht Sinn und Zweck ist wenn ich mit einem bestimmten Namen einloggen will.
So wurde die komplette Eingabe in einer Liste gespeichert und ich konnte Sie weiter verwenden.

So hab ich es jedenfalls verstanden was BackJack mir damit sagen wollte

2. Dient ja nur zu Test Zwecken
3. Gute Frage, habe keine Antwort darauf
4. Alles lässt sich leicht sagen bzw. schreiben. Ich wusste das es mit AND verknüpfen kann aber wenn man nicht auf den richtigen Syntax kommt versuch ich halt einer Alternative.
Schließlich gibt es nicht nur DIE EINE Lösung sondern verschiedene

Und wie ich es schon geschrieben habe, es handelt sich hierbei ja nur um eine Funktion zum testen und lernen und das man Passwörter nicht im Klartext speichert is mir sehr wohl bewusst. Aber da ich noch mit Python noch nicht soviel Ahnung habe arbeite ich mich langsam an alles ran. Ich bin ein blutiger Anfänger was Python betrifft.
Ich bitte daher um Nachsicht.
BlackJack

@Kalli87: Das Einzelwerte in eine Liste (oder eine andere Sequenz) gesteckt werden müssen für den Aufruf stimmt, aber nicht *so*. Das funktioniert doch schon nicht mehr wenn man die Funktion ein zweites mal aufruft weil dann jeweils zwei Elemente in der Liste stehen. Man würde hier die Liste direkt beim Aufruf als literale Liste erstellen und nicht erst an einen Namen binden. Die Liste wird ja ansonsten weder davor noch danach irgendwo gebraucht.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: Warum die for-Schleifen? Wenn eine Abfrage nur ein Element ergeben kann, dann holt man die sich mit ".fetchone"; der Benutzername sollte ja eindeutig sein. Magische Indizes wie "dsatz[0]" sollte man vermeiden, wenn man ein "SELECT *" hat, das funktioniert nur so lange man die Datenbank nicht mal umbaut.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Kalli87 hat geschrieben:Ich bitte daher um Nachsicht.
Klar. Sieh die Kritik bitte auch als Kritik am Code und nicht als Kritik an dir als Person. Das wird schon.

Mit jahrzehntelanger eigener Programmiererfahrung neigt man dazu, die Schwierigkeiten eines Anfängers zu unterschätzen.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Sirius3
Ich hab es mal geändert und hoffe mal das es so in die richtige Richtung geht, ".fetchone" hatte ich vorher nicht gehört oder gelesen
und musste danach erstmal google befragen und mich belesen, am ende kam das dabei raus.

@/istme
Keine Angst, mir ist bewusst das die Kritik an den Code ging, kann ich auch verstehen bei dem was ich dort geschrieben habe.

Jetzt mal eine Frage zu dem Aktuellem Stand des Codes:
Wieso komm ich nicht in den elif Zweig? Eine Ausgabe bekomm ich nur wenn wenn User und Passwort richtig eingegeben wurden
ansonsten passiert nichts.

Code: Alles auswählen

def login():

    connection = psycopg2.connect("dbname=sqltest")
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM mitarbeiter WHERE loginname = %s AND passwort = %s ", (benutzername.get(), passwort.get()))
    row = cursor.fetchone()

    if row is not None:
        if benutzername.get() == row[0] and passwort.get() == row[1]:
            print("funktioniert")

        elif passwort.get() != row[1]:
             print("passwort falsch")

        elif benutzername.get() != row[0]:
            print("user nicht vorhanden")
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: die ganzen if-Abfragen ab Zeile 9 sind überflüssig, weil Du nur einen Datensatz von der Datenbank bekommst, wenn sowohl benutzername als auch passwort stimmen. Du mußt also einen else-Zweig zu "row is not None" schreiben.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Sirius3
Danke :)
Antworten