diff --git a/datasette/views/table.py b/datasette/views/table.py index 0a908c69..8d35a4d4 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -721,6 +721,8 @@ async def display_columns_and_rows( # Unless we are a view, the first column is a link - either to the rowid # or to the simple or compound primary key if link_column: + # NULL keys may be duplicated and encode like a real string key. + has_null_pk = bool(pks) and any(row[pk] is None for pk in pks) is_special_link_column = len(pks) != 1 pk_path = path_from_row_pks(row, pks, not pks, False) row_path = path_from_row_pks(row, pks, not pks) @@ -729,9 +731,9 @@ async def display_columns_and_rows( if row_label and row_label != pk_path: row_action_label = f"{pk_path} {row_label}" table_path = datasette.urls.table(database_name, table_name) - row_link = ( - f'{markupsafe.escape(pk_path)!s}' - ) + row_link = markupsafe.escape(pk_path) + if not has_null_pk: + row_link = f'{markupsafe.escape(pk_path)!s}' edit_icon = ( '