datasette
datasette copied to clipboard
Documentation and unit tests for urls.row() urls.row_blob() methods
https://github.com/simonw/datasette/blob/5db7ae3ce165ded57c7fb1cfbdb3258b1cf06c10/datasette/app.py#L1307-L1313
The row_path part of these really isn't very user friendly, since you need to properly URL-encode the values. The safest way to do so is by calling this obscure, undocumented utility function: https://github.com/simonw/datasette/blob/f0bd2d05f5f7832df4879822afb99d2096c00d48/datasette/utils/init.py#L84-L98
This feels like it should be improved before I turn it into a documented API.
(Note that this API deals with a row that is a potentially-nested dictionary - not with a sqlite3.Row object.)
Also related: row is now available to render_cell() hook as-of this issue:
- https://github.com/simonw/datasette/issues/1300
I'm considering changing these functions to accept the row object itself:
def row(self, database, table, row):
...
def row_blob(self, database, table, row, column):
...
Just one catch: in order to generate the correct row_path we need to know the primary keys for that table. We can look those up based on having access to database and table, but doing so requires an await ... operation - and these functions are not async.
None of the potential solutions for that problem are particularly appealing:
- Make these URL generation methods
async- should the other ones beasynctoo for consistency? - Have some kind of mechanism that calculates and caches the
pksfor each table somewhere which can then be accessed here without anasynccall - Require
pksis passed to these methods, having been looked up elsewhere. This is a bit gross but may end up being the best solution
If I do require pks to be passed here, maybe I could make those available to the render_cell() plugin hook to at least make this a bit more pleasant for plugin authors to use?
Current hook: https://docs.datasette.io/en/latest/plugin_hooks.html#render-cell-row-value-column-table-database-datasette
https://github.com/simonw/datasette/blob/035dc5e7b95142d4a700819a8cc4ff64aefe4efe/datasette/hookspecs.py#L62-L64
The hook is called in two places in the codebase - when rendering a table (pks variable is already in scope here):
https://github.com/simonw/datasette/blob/6373bb341457e5becfd5b67792ac2c8b9ed7c384/datasette/views/table.py#L897-L904
And when rendering an arbitrary query:
https://github.com/simonw/datasette/blob/6373bb341457e5becfd5b67792ac2c8b9ed7c384/datasette/views/database.py#L377-L384
Note that in that second one table is None (which is also called out in the documentation) - pks would be None here too.
I think the best way to do this is to change the method signatures to:
def row(self, database, table, row, pks):
...
def row_blob(self, database, table, row, pks, column):
...
But do I need to pass the use_rowid boolean here as well, as used by def path_from_row_pks(row, pks, use_rowid, quote=True)? Or can I derive that from the fact that pks is an empty tuple?