diff --git a/datasette/static/app.css b/datasette/static/app.css
index bae091b8..cc33277a 100644
--- a/datasette/static/app.css
+++ b/datasette/static/app.css
@@ -345,3 +345,8 @@ p.zero-results {
padding: 0.5em;
font-style: italic;
}
+
+/* Value types */
+.type-float, .type-int {
+ color: #666;
+}
\ No newline at end of file
diff --git a/datasette/templates/_table.html b/datasette/templates/_table.html
index 42c37c55..8fee77b2 100644
--- a/datasette/templates/_table.html
+++ b/datasette/templates/_table.html
@@ -21,7 +21,7 @@
{% for row in display_rows %}
{% for cell in row %}
- | {{ cell.value }} |
+ {{ cell.value }} |
{% endfor %}
{% endfor %}
diff --git a/datasette/views/table.py b/datasette/views/table.py
index c07447d3..51b7aa2f 100644
--- a/datasette/views/table.py
+++ b/datasette/views/table.py
@@ -112,6 +112,7 @@ class RowTableShared(DataView):
cells.append(
{
"column": pks[0] if len(pks) == 1 else "Link",
+ "value_type": "link",
"is_special_link_column": is_special_link_column,
"raw": pk_path,
"value": jinja2.Markup(
@@ -192,7 +193,16 @@ class RowTableShared(DataView):
if truncate_cells and len(display_value) > truncate_cells:
display_value = display_value[:truncate_cells] + u"\u2026"
- cells.append({"column": column, "value": display_value, "raw": value})
+ cells.append(
+ {
+ "column": column,
+ "value": display_value,
+ "raw": value,
+ "value_type": "none"
+ if value is None
+ else str(type(value).__name__),
+ }
+ )
cell_rows.append(Row(cells))
if link_column:
diff --git a/tests/test_html.py b/tests/test_html.py
index 564365ce..a3388c2d 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -505,16 +505,16 @@ def test_table_html_simple_primary_key(app_client):
assert ["nofollow"] == a["rel"]
assert [
[
- '1 | ',
- 'hello | ',
+ '1 | ',
+ 'hello | ',
],
[
- '2 | ',
- 'world | ',
+ '2 | ',
+ 'world | ',
],
[
- '3 | ',
- '\xa0 | ',
+ '3 | ',
+ '\xa0 | ',
],
] == [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")]
@@ -578,9 +578,12 @@ def test_row_html_simple_primary_key(app_client):
assert response.status == 200
table = Soup(response.body, "html.parser").find("table")
assert ["id", "content"] == [th.string.strip() for th in table.select("thead th")]
- assert [['1 | ', 'hello | ']] == [
- [str(td) for td in tr.select("td")] for tr in table.select("tbody tr")
- ]
+ assert [
+ [
+ '1 | ',
+ 'hello | ',
+ ]
+ ] == [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")]
def test_table_not_exists(app_client):
@@ -599,14 +602,14 @@ def test_table_html_no_primary_key(app_client):
]
expected = [
[
- '{} | '.format(
+ '{} | '.format(
i, i
),
- '{} | '.format(i),
- '{} | '.format(i),
- 'a{} | '.format(i),
- 'b{} | '.format(i),
- 'c{} | '.format(i),
+ '{} | '.format(i),
+ '{} | '.format(i),
+ 'a{} | '.format(i),
+ 'b{} | '.format(i),
+ 'c{} | '.format(i),
]
for i in range(1, 51)
]
@@ -633,11 +636,11 @@ def test_row_html_no_primary_key(app_client):
]
expected = [
[
- '1 | ',
- '1 | ',
- 'a1 | ',
- 'b1 | ',
- 'c1 | ',
+ '1 | ',
+ '1 | ',
+ 'a1 | ',
+ 'b1 | ',
+ 'c1 | ',
]
]
assert expected == [
@@ -658,10 +661,10 @@ def test_table_html_compound_primary_key(app_client):
assert a["href"].endswith("/compound_primary_key?_sort={}".format(expected_col))
expected = [
[
- 'a,b | ',
- 'a | ',
- 'b | ',
- 'c | ',
+ 'a,b | ',
+ 'a | ',
+ 'b | ',
+ 'c | ',
]
]
assert expected == [
@@ -675,14 +678,14 @@ def test_table_html_foreign_key_links(app_client):
table = Soup(response.body, "html.parser").find("table")
expected = [
[
- '1 | ',
- 'hello\xa01 | ',
- '1 | ',
+ '1 | ',
+ 'hello\xa01 | ',
+ '1 | ',
],
[
- '2 | ',
- '\xa0 | ',
- '\xa0 | ',
+ '2 | ',
+ '\xa0 | ',
+ '\xa0 | ',
],
]
assert expected == [
@@ -696,9 +699,9 @@ def test_table_html_disable_foreign_key_links_with_labels(app_client):
table = Soup(response.body, "html.parser").find("table")
expected = [
[
- '1 | ',
- '1 | ',
- '1 | ',
+ '1 | ',
+ '1 | ',
+ '1 | ',
]
]
assert expected == [
@@ -712,8 +715,8 @@ def test_table_html_foreign_key_custom_label_column(app_client):
table = Soup(response.body, "html.parser").find("table")
expected = [
[
- '1 | ',
- 'world2\xa01 | ',
+ '1 | ',
+ 'world2\xa01 | ',
]
]
assert expected == [
@@ -754,9 +757,9 @@ def test_row_html_compound_primary_key(app_client):
]
expected = [
[
- 'a | ',
- 'b | ',
- 'c | ',
+ 'a | ',
+ 'b | ',
+ 'c | ',
]
]
assert expected == [
@@ -771,14 +774,14 @@ def test_compound_primary_key_with_foreign_key_references(app_client):
table = Soup(response.body, "html.parser").find("table")
expected = [
[
- '1,feline | ',
- '1\xa01 | ',
- 'feline | ',
+ '1,feline | ',
+ '1\xa01 | ',
+ 'feline | ',
],
[
- '2,canine | ',
- '2\xa02 | ',
- 'canine | ',
+ '2,canine | ',
+ '2\xa02 | ',
+ 'canine | ',
],
]
assert expected == [
@@ -799,16 +802,16 @@ def test_view_html(app_client):
assert ths[1].string.strip() == "upper_content"
expected = [
[
- 'hello | ',
- 'HELLO | ',
+ 'hello | ',
+ 'HELLO | ',
],
[
- 'world | ',
- 'WORLD | ',
+ 'world | ',
+ 'WORLD | ',
],
[
- '\xa0 | ',
- '\xa0 | ',
+ '\xa0 | ',
+ '\xa0 | ',
],
]
assert expected == [
@@ -1079,9 +1082,9 @@ def test_binary_data_display(app_client):
table = Soup(response.body, "html.parser").find("table")
expected_tds = [
[
- '1 | ',
- '1 | ',
- '<Binary\xa0data:\xa019\xa0bytes> | ',
+ '1 | ',
+ '1 | ',
+ '<Binary\xa0data:\xa019\xa0bytes> | ',
]
]
assert expected_tds == [
@@ -1154,20 +1157,20 @@ def test_metadata_sort(app_client):
rows = [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")]
expected = [
[
- '3 | ',
- 'Detroit | ',
+ '3 | ',
+ 'Detroit | ',
],
[
- '2 | ',
- 'Los Angeles | ',
+ '2 | ',
+ 'Los Angeles | ',
],
[
- '4 | ',
- 'Memnonia | ',
+ '4 | ',
+ 'Memnonia | ',
],
[
- '1 | ',
- 'San Francisco | ',
+ '1 | ',
+ 'San Francisco | ',
],
]
assert expected == rows
@@ -1189,12 +1192,12 @@ def test_metadata_sort_desc(app_client):
rows = [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")]
expected = [
[
- '2 | ',
- 'Paranormal | ',
+ '2 | ',
+ 'Paranormal | ',
],
[
- '1 | ',
- 'Museum | ',
+ '1 | ',
+ 'Museum | ',
],
]
assert expected == rows