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 beasync
too for consistency? - Have some kind of mechanism that calculates and caches the
pks
for each table somewhere which can then be accessed here without anasync
call - Require
pks
is 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?