diff --git a/datasette/views/row.py b/datasette/views/row.py index 6e09f30e5d..834727f6b9 100644 --- a/datasette/views/row.py +++ b/datasette/views/row.py @@ -10,7 +10,7 @@ ) import json import sqlite_utils -from .table import display_columns_and_rows +from .table import display_columns_and_rows, expand_labels class RowView(DataView): @@ -42,6 +42,11 @@ async def data(self, request, default_labels=False): if not rows: raise NotFound(f"Record not found: {pk_values}") + # Expand labeled columns if requested + rows, _ = await expand_labels( + self.ds, database, table, columns, rows, request.args, default_labels + ) + async def template_data(): display_columns, display_rows = await display_columns_and_rows( self.ds, diff --git a/datasette/views/table.py b/datasette/views/table.py index 8c133c26f2..919022d9c4 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -324,6 +324,73 @@ async def display_columns_and_rows( return columns, cell_rows +async def expand_labels( + datasette, + database_name, + table_name, + columns, + rows, + request_args, + default_labels, +): + """Expands labeled columns if requested""" + db = datasette.databases[database_name] + expanded_columns = [] + # List of (fk_dict, label_column-or-None) pairs for that table + expandable_columns = [] + for fk in await db.foreign_keys_for_table(table_name): + label_column = await db.label_column_for_table(fk["other_table"]) + expandable_columns.append((fk, label_column)) + + columns_to_expand = None + try: + all_labels = value_as_boolean(request_args.get("_labels", "")) + except ValueError: + all_labels = default_labels + # Check for explicit _label= + if "_label" in request_args: + columns_to_expand = request_args.getlist("_label") + if columns_to_expand is None and all_labels: + # expand all columns with foreign keys + columns_to_expand = [fk["column"] for fk, _ in expandable_columns] + + if columns_to_expand: + expanded_labels = {} + for fk, _ in expandable_columns: + column = fk["column"] + if column not in columns_to_expand: + continue + if column not in columns: + continue + expanded_columns.append(column) + # Gather the values + column_index = columns.index(column) + values = [row[column_index] for row in rows] + # Expand them + expanded_labels.update( + await datasette.expand_foreign_keys( + database_name, table_name, column, values + ) + ) + if expanded_labels: + # Rewrite the rows + new_rows = [] + for row in rows: + new_row = CustomRow(columns) + for column in row.keys(): + value = row[column] + if (column, value) in expanded_labels and value is not None: + new_row[column] = { + "value": value, + "label": expanded_labels[(column, value)], + } + else: + new_row[column] = value + new_rows.append(new_row) + rows = new_rows + return rows, expanded_columns + + class TableInsertView(BaseView): name = "table-insert" @@ -1164,59 +1231,15 @@ async def table_view_data( rows = list(results.rows) # Expand labeled columns if requested - expanded_columns = [] - # List of (fk_dict, label_column-or-None) pairs for that table - expandable_columns = [] - for fk in await db.foreign_keys_for_table(table_name): - label_column = await db.label_column_for_table(fk["other_table"]) - expandable_columns.append((fk, label_column)) - - columns_to_expand = None - try: - all_labels = value_as_boolean(request.args.get("_labels", "")) - except ValueError: - all_labels = default_labels - # Check for explicit _label= - if "_label" in request.args: - columns_to_expand = request.args.getlist("_label") - if columns_to_expand is None and all_labels: - # expand all columns with foreign keys - columns_to_expand = [fk["column"] for fk, _ in expandable_columns] - - if columns_to_expand: - expanded_labels = {} - for fk, _ in expandable_columns: - column = fk["column"] - if column not in columns_to_expand: - continue - if column not in columns: - continue - expanded_columns.append(column) - # Gather the values - column_index = columns.index(column) - values = [row[column_index] for row in rows] - # Expand them - expanded_labels.update( - await datasette.expand_foreign_keys( - database_name, table_name, column, values - ) - ) - if expanded_labels: - # Rewrite the rows - new_rows = [] - for row in rows: - new_row = CustomRow(columns) - for column in row.keys(): - value = row[column] - if (column, value) in expanded_labels and value is not None: - new_row[column] = { - "value": value, - "label": expanded_labels[(column, value)], - } - else: - new_row[column] = value - new_rows.append(new_row) - rows = new_rows + rows, expanded_columns = await expand_labels( + datasette, + database_name, + table_name, + columns, + rows, + request.args, + default_labels, + ) _next = request.args.get("_next") diff --git a/tests/test_table_html.py b/tests/test_table_html.py index e1886dab5a..c0e0269b1d 100644 --- a/tests/test_table_html.py +++ b/tests/test_table_html.py @@ -632,6 +632,38 @@ async def test_table_html_foreign_key_links(ds_client): ] +@pytest.mark.asyncio +async def test_row_html_foreign_key_links(ds_client): + response = await ds_client.get("/fixtures/foreign_key_references/1") + assert response.status_code == 200 + table = Soup(response.text, "html.parser").find("table") + actual = [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")] + assert actual == [ + [ + '1', + 'hello\xa01', + '-\xa03', + '1', + 'a', + 'b', + ], + ] + response = await ds_client.get("/fixtures/foreign_key_references/2") + assert response.status_code == 200 + table = Soup(response.text, "html.parser").find("table") + actual = [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")] + assert actual == [ + [ + '2', + '\xa0', + '\xa0', + '\xa0', + '\xa0', + '\xa0', + ], + ] + + @pytest.mark.asyncio async def test_table_html_foreign_key_facets(ds_client): response = await ds_client.get(