Eingabe auf String und/oder Integer überprüfen

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.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Grüße,

Ich möchte ein ganz normales Entry-Feld auf deren Eingabe überprüfen ob es sich um ein String oder um ein Integer handelt. Hängt damit zusammen das an der Eingabe die Datenbankabfrage gekoppelt ist.

Code: Alles auswählen

self.cursor.execute("select * from patient, bilder where patient.patnu= %s and bilder.patnu=%s", (self.eingabe.get(), self.eingabe.get()))
Hier in dem Beispiel ist es so das dort die Abfrage sich bereits auf Integer beschränkt da ich nur nach der Patientennummer suche.
Will ich aber auch nach dem Namen suchen geht es ja nicht und ja ich weiß das hier der Beispielcode nicht dafür ausgelegt ist um nach Namen zu suchen. Aber zum testen hab ich es bereits probiert und gab halt den Fehler das es nicht geht da es sich bei der Eingabe nicht um ein Integer handelt.

Bzw. habt ihr einen Tipp wie ich die Abfrage so gestalten kann das ich nach Namen und Nummern suchen kann?
BlackJack

@Kalli87: Wandle die Zeichenkette einfach in eine ganze Zahl um. Wenn es dabei einen `ValueError` gibt, dann ist die Zeichenfolge keine ganze Zahl.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Man sollte "SELECT *"-Queries übrigens vermeiden. Schreibe besser explizit hin, welcher Felder Du sehen willst :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Hyperion
Is richtig aber leider brauch ich alle Daten ;)

@BlackJack
Ich versuchs mal, danke
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kalli87 hat geschrieben:@Hyperion
Is richtig aber leider brauch ich alle Daten ;)
Ja und? Dann gib eben alle Spalten an!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Kalli87: Dann schreibe alle Spalten die Du brauchst explizit hin. Wobei *alle* brauchst Du nicht denn mindestens die Patientennummer ist in dem '*' ja zweimal enthalten weil sie in beiden Tabellen steht und hier zum verbinden der beiden Tabellen verwendet wird, also den gleichen Wert im Ergebnis haben wird.

Die Spalten hinzuschreiben hat den Vorteil das man im Quelltext sieht was dort abgefragt wird und nicht in der Datenbank nachschauen oder sich das merken muss, und wenn man das Schema von mindestens einer der beiden Tabellen mal ändert ist das geheule gross weil die '*'-Abfrage weiterhin funktioniert, der Code der das Ergebnis danach verarbeitet aber auf die Fresse fallen wird. Und dann darf man all diese Stellen im Code suchen die betroffen sind. Wenn man die Spalten in der Abfrage explizit hinschreibt, dann funktioniert die Abfrage schon nicht, falls eine Spalte in der DB nicht mehr existiert, oder sie funktioniert ganz einfach weiter wie vorher falls Spalten bei den Tabellen hinzugekommen sind.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Blackjack
Gutes Argument!

@Hyperion
Nicht gleich sauer werden :?
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Überlege mal was passiert, wenn jemand
"123 or 2<3"
in die Eingabe schreibt.
Kalli87 hat geschrieben:Ich möchte ein ganz normales Entry-Feld auf deren Eingabe überprüfen ob es sich um ein String oder um ein Integer handelt.
Das geht so:

Code: Alles auswählen

def is_number(str_value):
    try:
        int(str_value.strip())
        return True
    except:
        return False
    
print is_number("123") # True
print is_number(" 123 ") # True
print is_number(" 1 23 ") # False
print is_number(" 123X ") # False
a fool with a tool is still a fool, www.magben.de, YouTube
BlackJack

@MagBen: Was soll bei der Eingabe "123 or 2<3" passieren? Im Quelltext im ersten Beitrag gar nichts bzw. die Datenbank wird sich beschweren dass man den Inhalt einer numerischen Spalte nicht mit einer Zeichenkette vergleichen kann. Das ist *keine* SQL-Injektion, weil die Zeichenkette ja nicht einfach so in die SQL-Anweisung hineinformatiert wird.

Die Funktion ist zwar nett, aber IMHO überflüssig, denn die wandelt die Eingabe um und im Erfolgsfall wird sie vom aufrufenden Code dann noch mal umgewandelt. Das kann man also gleich im Aufrufenden Code abhandeln.

Edit: @Kalli87: Man könnte übrigens auch SQLAlchemy verwenden, dann bekommt man alle Spalten ohne sie bei jeder Abfrage explizit hinschreiben zu müssen und auch das dynamische erzeugen und erweitern von Anfragen ist einfacher als sich SQL-Anfragen als Zeichenketten zusammenzubasteln. Ungetestet und entsprechende Model-Klassen für Patient und Bilder vorausgesetzt:

Code: Alles auswählen

        query = self.session.query(Patient).join(Image)
        user_query = self.query_entry.get()
        try:
            patient_number = int(user_query)
        except ValueError:
            query = query.filter_by(name=user_query)
        else:
            query = query.filter_by(patient_number=patient_number)
        patients = query.all()
        for patient in patients:
            print patient.name, patient.patient_number
            for image in patient.images:
                print '  >', image.path
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kalli87 hat geschrieben: Nicht gleich sauer werden :?
Öh... das war ich gar nicht :-) Das hätte ich durch einen Smiley kenntlich gemacht ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Zuviel input :?
Muss erstmal mit dem ValueError klar kommen bzw. näher in Erfahrung bringen wie das ganze funktioniert und wie ich das ganze bei anwenden kann. Vorher is alles andere zuviel :D aber Danke für die ganzen Tipps :)
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Ich melde mich zurück vom grübeln und probieren von BlackJacks Beispielcode.
Mir tut sich da ein Problem auf wenn ich sage:

Code: Alles auswählen

try:
    x = int(self.eingabe.get())
    self.cursor.execute("select * from patient, bilder where patient.patnu= %s and bilder.patnu=%s", (self.eingabe.get(), self.eingabe.get()))

    (der restliche Code der hier liegt lass ich mal weg)

except ValueError:
    self.cursor.execute("select * from patient, bilder where patient.klein_name=%s and bilder.patnu=patient.patnu", (self.eingabe.get()))

    (hier das gleiche mit dem restlichen sachen)
Soweit ich verstanden habe wird doch im "Try" wie bei einer "if" Anweisung die Ausnahmebehandlung eingetragen. Trifft diese zu wird doch die Anweisung im "Try" vollständig ausgeführt und "except" wird übergangen wie bei "else". Lieg ich doch richtig, oder? Also is die Funktionsweise doch wie bei einer "If-Anweisung" aufgebaut.

Was ich jetzt aber nicht verstehe ist das wenn ich jetzt keine Nummer eingebe sondern ein Namen das ich einen Fehler bekomme.

Code: Alles auswählen

TypeError: not all arguments converted during string formatting
Hängt sicher damit zusammen das im "try" ja int(self.eingabe.get()) stehen habe aber wenn ich int weglasse geht nix mehr so kann ich wenigstens nach der Patientennummer suchen.

Ps.: Ich weiß ich hab die select-Abfrage noch nicht überarbeitet, Ich wollte erst das die Funktion richtig funktioniert.
BlackJack

@Kalli87: Im ``try``-Block sollte möglichst wenig stehen denn sonst wächst die Gefahr das die Ausnahme auch in anderem Code ausgelöst wird und nicht nur beim Versuch die Eingabe in ein `int` zu wandeln. Die Abfrage und den Code danach würde man also eher in einen ``else``-Block schreiben.

Die Ausnahme bekommst Du weil `execute()` als zweites Argument eine Sequenz mit den einzelnen Werten erwartet. Also auch wenn das nur *ein* Wert ist, muss der in einem Tupel oder einer Liste, oder etwas ähnlichem stecken. Du übergibst dort eine Zeichenkette die ihrerseits eine Sequenz von Buchstaben ist. Wenn Du da also 'Meier' eingegeben hast, dann verwendet das Datenbankmodul das erste Element, also das 'M' und beschwert sich dann das für die Elemente 'e', 'i', 'e', und 'r' gar keine Platzhalter mehr vorhanden sind.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

BlackJack hat geschrieben: Die Ausnahme bekommst Du weil `execute()` als zweites Argument eine Sequenz mit den einzelnen Werten erwartet. Also auch wenn das nur *ein* Wert ist, muss der in einem Tupel oder einer Liste, oder etwas ähnlichem stecken. Du übergibst dort eine Zeichenkette die ihrerseits eine Sequenz von Buchstaben ist. Wenn Du da also 'Meier' eingegeben hast, dann verwendet das Datenbankmodul das erste Element, also das 'M' und beschwert sich dann das für die Elemente 'e', 'i', 'e', und 'r' gar keine Platzhalter mehr vorhanden sind.
Ach ja, da war ja was! Das Problem hatte ich schon mal ^^ muss ich nur mal gucken wie ich das gelöst hatte ;)
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Guten Morgen,

Ich muss gleich mal früh schon etwas fragen woran das liegen kann.

Code: Alles auswählen

self.cursor.execute("select * from patient, bilder where patient.patnu= %s and bilder.patnu=%s", suchfu)
IndexError: list index out of range

Code: Alles auswählen

suchfu=[]
            suchfu.append(self.eingabe.get())
So hatte ich das Problem immer mit dem Elementen und den Platzhaltern gelöst, woran scheitert es nun?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

In deinem Fall hat das Statement zwei Platzhalter und erwartet daher natürlich auch zwei Werte. Zu kurze Listen lassen sich auch einfacher zusammenbauen, dazu braucht es kein append. Vielleicht solltest du noch einmal das Grundlagentutorial aus der Dokumentation durchgehen.
Das Leben ist wie ein Tennisball.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Nenn mir eine alternative zu append, mir is keine bekannt weiter. In den Büchern, die mir zu Verfügung stehen, wird append verwendet um eine liste so zu erstellen. Und per Hand anlegen is ja blödsinn.
Das mit den Platzehaltern is klar, gab zwar auch da nen fehler hab den aber gelöst.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kalli87 hat geschrieben:In den Büchern, die mir zu Verfügung stehen, wird append verwendet um eine liste so zu erstellen.
Wenn das wirklich für *den* Fall gezeigt wird, ist das Unsinn!
Kalli87 hat geschrieben: Und per Hand anlegen is ja blödsinn.
Ich vermute Du meinst mit "per Hand" das *richtige* Vorgehen - aber das ist eben *kein* Blödsinn ;-)

Code: Alles auswählen

[self.eingabe.get()] * 2
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17768
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: wobei man hier ja sinnvollerweise erst den join machen würde und dann mit der externen Variable vergleichen

Code: Alles auswählen

self.cursor.execute("select * from patient, bilder where bilder.patnu=patient.patnu and patient.patnu=%s", [self.eingabe.get()])
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Also diese Varianten von
[self.eingabe.get()]
und
[self.eingabe.get()*2]
sind mir echt nicht bekannt.

Kann mir einer genauer erklären wie das funktioniert?
Antworten