Static Data

Serving hard-coded snail records before introducing a real database

Concepts

Representing a record as a dataclass

Rendering records as an HTML table

A route that serves the table

Check for Understanding

What does @dataclass do, and how is a dataclass different from a plain dictionary?

A plain dictionary is untyped and has no fixed structure; you can add or remove keys freely. A dataclass enforces structure at definition time and provides attribute-style access (record.diameter instead of record["diameter"]). The @dataclass decorator reads the field names and type annotations you declare and generates an __init__ method (so you can write Snail(site="north", diameter=12.3)) along with __repr__ and __eq__.

If a field in a dataclass has type float | None, what does that mean, and how would you handle it when rendering?

It means the field can hold a floating-point number or the value None (absent/unknown). When rendering in htpy, you must check before converting to a string: for example, str(record.diameter) if record.diameter is not None else "—". Passing None directly to htpy or formatting it without checking would display the string "None", which is confusing to readers.

Why might you prefer hard-coded sample data over querying a real database during early development?

Hard-coded data is always available, never changes between runs, and requires no setup. You can render and test the table layout before the database schema is finalized or data is loaded. It also makes bugs easier to isolate: if something is wrong, you know the data is not the cause. Of course, you must remember to replace it later.

If you add a new field to the dataclass, what else in the code do you need to update?

You need to update: (1) any hard-coded sample data that creates instances of the dataclass (the new field needs a value or a default), (2) the HTML table renderer (add a column header and a cell for the new field), (3) any SQL insert and select statements in later lessons that reference specific columns, and (4) any tests that construct instances.

Exercises

Add a new field

Add a notes: str field with a default value of "" to the snail measurement dataclass. Update the sample records and the table renderer to include it. Prompt the LLM for help and check whether its output covers all the places that need updating; do not just accept that it is complete.

Sort the table

Add a query parameter sort that controls which column the table is sorted by (e.g., ?sort=diameter). Write out what the sorting logic should do before prompting the LLM to implement it. Verify that it handles the case where sort refers to a field that does not exist.

Color-code rows

Prompt the LLM to add a CSS class (e.g., mutated) to table rows where the mutation field is True, and to style those rows with a distinct background color. Check that the class is applied only to the correct rows, and that the color passes a basic contrast check against the text.

Export as CSV

Add a /data.csv route that returns the hard-coded sample records as a CSV file. The response must set Content-Type: text/csv and include a header row. Test it with curl -o records.csv http://localhost:8000/data.csv and open the file in a spreadsheet application to verify the format.