From 27424e8981be7a5aff74aac69af8b72afcee64c7 Mon Sep 17 00:00:00 2001
From: sb123sb123 <152394158+sb123sb123@users.noreply.github.com>
Date: Sat, 26 Sep 2026 20:29:56 +0800
Subject: [PATCH] Avoid links for rows with NULL primary keys
Fixes #2145
---
datasette/views/table.py | 12 +++---
tests/test_table_html.py | 83 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 5 deletions(-)
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 = (
'