Kapitel 5 · Übung
Daten sicher ändern
Einen Wert an eine bekannte Abfrage binden
Der Katalog kann eine feste Frage beantworten, aber ein echtes Programm muss nach dem Inventarkennzeichen suchen, das der aufrufende Code liefert. Für diesen Durchlauf ruft Python die neue Funktion mit einem sichtbaren Kennzeichen auf:
find_item(connection, "TL-100")
Die Argumente sind eine bereits offene connection und der Textwert "TL-100". Öffne catalog_changes.py. Die Funktion enthält bereits eine vollständige Abfrage, deren WHERE-Bedingung ein Fragezeichen hat:
def find_item(connection, asset_tag):
statement = """
SELECT id, asset_tag, name, category, loan_days
FROM items
WHERE asset_tag = ?
"""
return connection.execute(statement).fetchone()
Das ? ist ein Platzhalter für einen Wert. Die SQL-Struktur bleibt fest, während Python den Wert separat liefert. Ändere nur die Rückgabezeile:
return connection.execute(statement, (asset_tag,)).fetchone()
Der Aufruf von execute hat jetzt zwei Argumente: die Anweisung und ein Tupel mit einem Element, das den Suchwert enthält.
| SQL-Position | Python-Argumentwert |
|---|---|
erstes und einziges ?, für asset_tag | erstes und einziges Element von (asset_tag,) |
Verfolge den Wert einmal durch den Aufruf. Python erhält "TL-100" als asset_tag. Die Anweisung enthält weiterhin WHERE asset_tag = ?; Python setzt das Kennzeichen nicht in diesen Text ein. Stattdessen transportiert (asset_tag,) den Wert "TL-100" neben der Anweisung, und die Datenbank ordnet diesen ersten Tupelwert dem ersten Platzhalter zu. Ein Kennzeichen mit Apostroph folgt genau demselben Weg. Ein fehlendes Kennzeichen ebenfalls: Es erzeugt einfach keine passende Zeile. Durch diese Trennung kann eine Anweisung alle drei Fälle behandeln, ohne ihre Form zu ändern.
Auch die übergebene connection ist wichtig. run_changes.py hat sie bereits geöffnet und den sichtbaren Katalog vorbereitet. Indem die Funktion dieselbe Verbindung verwendet, stellt sie eine Frage an den erwarteten Katalog, statt unbemerkt anderswo einen anderen zu erstellen.
Das Komma in (asset_tag,) ist wichtig. Klammern allein können einen Wert gruppieren, aber das Komma macht daraus ein Tupel mit einem Element, das die Datenbankschnittstelle einem Platzhalter zuordnen kann.
Klicke auf Run und finde die beiden exakten Aufrufe:
== catalog_changes.py: find_item ==
find_item(connection, "TL-100")
(3, 'TL-100', 'Cordless drill', 'tools', 7)
find_item(connection, "NO-404")
None
Das erste Ergebnis folgt der Reihenfolge der ausgewählten Spalten. Der zweite Aufruf verwendet dieselbe Anweisung mit einem anderen Wert und erhält None, weil keine Zeile passt.
run_changes.py bereitet für jede benannte Funktion einen neuen Katalog vor und gibt den Aufruf und das relevante Ergebnis aus. Lass diese Datei unverändert. Deine Funktion bleibt in catalog_changes.py und verwendet die Verbindung, die sie erhält.
Submit probiert gewöhnliche Kennzeichen, fehlende Kennzeichen, Apostrophe und Text aus, der wie SQL aussieht. Halte den vollständigen Wert außerhalb des Anweisungsstrings und übergib ihn unverändert als zweites Argument. Deine Funktion hat jetzt eine stabile Abfrage, die sicher nach vielen unterschiedlichen Werten suchen kann.
Aufgabe
Übergib in catalog_changes.py das Tupel (asset_tag,) als zweites Argument an connection.execute(statement, ...). Behalte die feste Abfrage bei und gib .fetchone() zurück.
Führe das Projekt aus, prüfe beide Aufrufe und reiche die Funktion ein.