diff --git a/datasette/app.py b/datasette/app.py index b6a3498a27..0b425c046d 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -524,7 +524,12 @@ async def display_columns_and_rows(self, database, table, description, rows, lin if table_info and expand_foreign_keys: foreign_keys = table_info['foreign_keys']['outgoing'] for fk in foreign_keys: - label_column = tables.get(fk['other_table'], {}).get('label_column') + label_column = ( + # First look for metadata.json definition: + table_metadata.get('label_column') + # Fall back to label_column from .inspect() detection: + or tables.get(fk['other_table'], {}).get('label_column') + ) if not label_column: # No label for this FK fks[fk['column']] = fk['other_table'] diff --git a/docs/metadata.rst b/docs/metadata.rst index 7872f88f79..c00f06d658 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -81,7 +81,7 @@ Column units are configured in the metadata like so:: Units are interpreted using Pint_, and you can see the full list of available units in Pint's `unit registry`_. You can also add `custom units`_ to the metadata, which will be registered with Pint:: - + { "custom_units": [ "decibel = [] = dB" @@ -119,6 +119,29 @@ This will restrict sorting of ``example_table`` to just the ``height`` and You can also disable sorting entirely by setting ``"sortable_columns": []`` +Specifying the label column for a table +--------------------------------------- + +Datasette's HTML interface attempts to display foreign key references as +labelled hyperlinks. By default, it looks for referenced tables that only have +two columns: a primary key column and one other. It assumes that the second +column should be used as the link label. + +If your table has more than two columns you can specify which column should be +used for the link label with the ``label_column`` property:: + + { + "databases": { + "database1": { + "tables": { + "example_table": { + "label_column": "title" + } + } + } + } + } + Generating a metadata skeleton ------------------------------ diff --git a/tests/fixtures.py b/tests/fixtures.py index 93942dda81..37e1f1b040 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -97,6 +97,9 @@ def generate_sortable_rows(num): 'frequency': 'Hz' } }, + 'custom_foreign_key_label': { + 'label_column': 'content2', + }, } }, } @@ -215,6 +218,12 @@ def extra_js_urls(): FOREIGN KEY ("f3") REFERENCES [simple_primary_key](id) ); +CREATE TABLE "custom_foreign_key_label" ( + pk varchar(30) primary key, + foreign_key_with_custom_label text, + FOREIGN KEY ("foreign_key_with_custom_label") REFERENCES [primary_key_multiple_columns](id) +); + CREATE TABLE units ( pk integer primary key, distance int, @@ -241,6 +250,7 @@ def extra_js_urls(): INSERT INTO foreign_key_references VALUES (1, 1, 1); INSERT INTO complex_foreign_keys VALUES (1, 1, 2, 1); +INSERT INTO custom_foreign_key_label VALUES (1, 1); INSERT INTO [table/with/slashes.csv] VALUES (3, 'hey'); diff --git a/tests/test_api.py b/tests/test_api.py index 4f1ed6f2b6..839dc1cb49 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -17,7 +17,7 @@ def test_homepage(app_client): assert response.json.keys() == {'test_tables': 0}.keys() d = response.json['test_tables'] assert d['name'] == 'test_tables' - assert d['tables_count'] == 13 + assert d['tables_count'] == 14 def test_database_page(app_client): @@ -80,6 +80,21 @@ def test_database_page(app_client): 'label_column': None, 'primary_keys': ['pk1', 'pk2', 'pk3'], }, { + 'columns': ['pk', 'foreign_key_with_custom_label'], + 'name': 'custom_foreign_key_label', + 'count': 1, + 'hidden': False, + 'foreign_keys': { + 'incoming': [], + 'outgoing': [{ + 'column': 'foreign_key_with_custom_label', + 'other_column': 'id', + 'other_table': 'primary_key_multiple_columns' + }], + }, + 'label_column': None, + 'primary_keys': ['pk'], + }, { 'columns': ['pk', 'foreign_key_with_label', 'foreign_key_with_no_label'], 'name': 'foreign_key_references', 'count': 1, @@ -115,6 +130,10 @@ def test_database_page(app_client): 'column': 'id', 'other_column': 'foreign_key_with_no_label', 'other_table': 'foreign_key_references' + }, { + 'column': 'id', + 'other_column': 'foreign_key_with_custom_label', + 'other_table': 'custom_foreign_key_label' }], 'outgoing': [] }, diff --git a/tests/test_html.py b/tests/test_html.py index 51e3d4eb28..ee12ce35ed 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -294,6 +294,19 @@ def test_table_html_foreign_key_links(app_client): assert expected == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')] +def test_table_html_foreign_key_custom_label_column(app_client): + response = app_client.get('/test_tables/custom_foreign_key_label', gather_request=False) + assert response.status == 200 + table = Soup(response.body, 'html.parser').find('table') + expected = [ + [ + '1', + 'world\xa01', + ] + ] + assert expected == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')] + + def test_row_html_compound_primary_key(app_client): response = app_client.get('/test_tables/compound_primary_key/a,b', gather_request=False) assert response.status == 200