Expose foreign key targets to create table UI

- Add foreignKeyTargetsPath to create table page data
- Filter hidden tables from database-level foreign key target results
- Update JSON API docs and tests for filtered targets
This commit is contained in:
Simon Willison 2026-06-18 08:13:28 -07:00
commit 21c156dfb1
4 changed files with 21 additions and 2 deletions

View file

@ -262,6 +262,9 @@ async def _create_table_ui_context(
return None
data = {
"path": "{}/-/create".format(datasette.urls.database(database_name)),
"foreignKeyTargetsPath": "{}/-/foreign-key-targets".format(
datasette.urls.database(database_name)
),
"databaseName": database_name,
"columnTypes": CREATE_TABLE_COLUMN_TYPES,
}
@ -836,7 +839,14 @@ class DatabaseForeignKeyTargetsView(BaseView):
):
return _error(["Permission denied: need create-table"], 403)
targets = (await db.execute(FOREIGN_KEY_TARGETS_SQL)).dicts()
hidden_tables = await db.execute_fn(
lambda conn: set(sqlite_hidden_table_names(conn))
)
targets = [
target
for target in (await db.execute(FOREIGN_KEY_TARGETS_SQL)).dicts()
if target["fk_table"] not in hidden_tables
]
return Response.json(
{
"ok": True,

View file

@ -2108,7 +2108,7 @@ The ``/<database>/-/foreign-key-targets`` endpoint returns the list of tables in
GET /<database>/-/foreign-key-targets
The response includes only tables with exactly one primary key column. Tables with compound primary keys and tables with no explicit primary key are omitted.
The response includes only tables with exactly one primary key column. Hidden tables, tables with compound primary keys and tables with no explicit primary key are omitted.
Each target includes the normalized SQLite type affinity for the primary key column in ``type``. The type is calculated using SQLite's documented affinity rules: ``INT`` maps to ``integer``; ``CHAR``, ``CLOB`` or ``TEXT`` maps to ``text``; ``BLOB`` or no type maps to ``blob``; ``REAL`` and floating-point declared types map to ``real``; everything else maps to ``numeric``.

View file

@ -1161,6 +1161,10 @@ async def test_foreign_key_targets(ds_write):
"create table compound (a integer, b integer, primary key (a, b))"
)
await db.execute_write("create table no_pk (name text)")
try:
await db.execute_write("create virtual table search_docs using fts5(body)")
except Exception:
pass
response = await ds_write.client.get(
"/data/-/foreign-key-targets",
@ -1203,6 +1207,10 @@ async def test_foreign_key_targets(ds_write):
},
],
}
assert not any(
target["fk_table"].startswith("search_docs_")
for target in response.json()["targets"]
)
@pytest.mark.asyncio

View file

@ -994,6 +994,7 @@ async def test_database_create_table_action_button_and_data():
assert database_data_from_soup(soup) == {
"createTable": {
"path": "/data/-/create",
"foreignKeyTargetsPath": "/data/-/foreign-key-targets",
"databaseName": "data",
"columnTypes": ["text", "integer", "float", "blob"],
},