Chapter 5 · practice
Change Data Safely
Bind a Value to a Familiar Query
The catalog can answer a fixed question, but a real program must search for whichever asset tag its caller provides. For this run, Python calls the new
find_item(connection, "TL-100")
The connection and the text "TL-100". Open catalog_changes.py. The function already contains a complete query whose WHERE
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()
The ? is a placeholder for one value. The SQL structure stays fixed while Python supplies the value separately. Change only the return line:
return connection.execute(statement, (asset_tag,)).fetchone()
The call to execute now has two arguments: the statement and a one-item
| SQL position | Python argument value |
|---|---|
first and only ?, for asset_tag | first and only element of (asset_tag,) |
Follow the value through the call once. Python receives "TL-100" as asset_tag. The statement still contains WHERE asset_tag = ?; Python does not paste the tag into that text. Instead, (asset_tag,) carries "TL-100" beside the statement, and the database matches that first tuple value to the first placeholder. An apostrophe-containing tag follows exactly the same path. A missing tag does too: it simply produces no matching row. This separation lets one statement handle all three cases without changing its shape.
The supplied connection matters as well. run_changes.py has already opened it and prepared the catalog you can see. By executing through that same connection, the function asks a question of the expected catalog rather than quietly creating a different one somewhere else.
The comma in (asset_tag,) matters. Parentheses alone can group one value, but the comma makes this a one-item tuple that the database interface can match to one placeholder.
Press Run and find the two exact calls:
== catalog_changes.py: find_item ==
find_item(connection, "TL-100")
(3, 'TL-100', 'Cordless drill', 'tools', 7)
find_item(connection, "NO-404")
None
The first result follows the selected column order. The second call uses the same statement with a different value and receives None because no row matches.
run_changes.py prepares a fresh catalog for each named function and prints the call and relevant result. Leave that file unchanged; your function stays in catalog_changes.py and uses the connection it receives.
Submit tries ordinary tags, missing tags, apostrophes, and SQL-looking text. Keep the complete value outside the statement
Task
In catalog_changes.py, pass (asset_tag,) as the second connection.execute(statement, ...). Keep the fixed query and return .fetchone().
Run the project, check both calls, and submit the