Convert a CSV to an HTML table¶
Problem. You have CSV data — from a file, an upload, or an API — and want it on a page as a styled table.
Solution. Iterate rows, wrap the first row in <th> tags and
the rest in <td>, and stream the result.
import csv
from io import StringIO
from tagz import html, Page, Style
source = StringIO(
"id,name,country\n"
"1,Ada,UK\n"
"2,Grace,USA\n"
"3,Linus,FI\n"
)
reader = csv.reader(source)
rows = list(reader)
table = html.table(
border="1",
style=Style(border_collapse="collapse"),
)
table.append(html.tr(*map(html.th, rows[0])))
for row in rows[1:]:
table.append(html.tr(*map(html.td, row)))
page = Page(
body_element=html.body(html.h1("People"), table),
head_elements=(html.title("People"),),
)
out = page.to_html5()
assert "<th>id</th><th>name</th><th>country</th>" in out
assert "<td>Ada</td>" in out
assert 'style="border-collapse: collapse;"' in out
Stream the file¶
For multi-megabyte CSVs, avoid materialising every row before rendering. Build the table tag lazily and stream the output:
import csv
from io import StringIO
from tagz import html, Style
def render_table(reader):
rows = iter(reader)
head = next(rows)
table = html.table(
html.tr(*map(html.th, head)),
border="1",
style=Style(border_collapse="collapse"),
)
for row in rows:
table.append(html.tr(*map(html.td, row)))
return table
reader = csv.reader(StringIO("a,b\n1,2\n3,4\n"))
chunks = list(render_table(reader).iter_chunk(chunk_size=64))
assert "".join(chunks).startswith("<table")
assert "<th>a</th>" in "".join(chunks)
(You can replace iter_chunk with iter_lines for log-friendly
output.)