id,page,ref,title,content,breadcrumbs,references plugin_hooks:plugin-hook-canned-queries,plugin_hooks,plugin-hook-canned-queries,"canned_queries(datasette, database, actor)","datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) , or to execute SQL queries. database - string The name of the database. actor - dictionary or None The currently authenticated actor . Use this hook to return a dictionary of additional canned query definitions for the specified database. The return value should be the same shape as the JSON described in the canned query documentation. from datasette import hookimpl @hookimpl def canned_queries(datasette, database): if database == ""mydb"": return { ""my_query"": { ""sql"": ""select * from my_table where id > :min_id"" } } The hook can alternatively return an awaitable function that returns a list. Here's an example that returns queries that have been stored in the saved_queries database table, if one exists: from datasette import hookimpl @hookimpl def canned_queries(datasette, database): async def inner(): db = datasette.get_database(database) if await db.table_exists(""saved_queries""): results = await db.execute( ""select name, sql from saved_queries"" ) return { result[""name""]: {""sql"": result[""sql""]} for result in results } return inner The actor parameter can be used to include the currently authenticated actor in your decision. Here's an example that returns saved queries that were saved by that actor: from datasette import hookimpl @hookimpl def canned_queries(datasette, database, actor): async def inner(): db = datasette.get_database(database) if actor is not None and await db.table_exists( ""saved_queries"" ): results = await db.execute( ""select name, sql from saved_queries where actor_id = :id"", {""id"": actor[""id""]}, ) return { result[""name""]: {""sql"": result[""sql""]} for result in results } return inner Example: datasette-saved-queries","[""Plugin hooks""]","[{""href"": ""https://datasette.io/plugins/datasette-saved-queries"", ""label"": ""datasette-saved-queries""}]" plugin_hooks:plugin-hook-actors-from-ids,plugin_hooks,plugin-hook-actors-from-ids,"actors_from_ids(datasette, actor_ids)","datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) , or to execute SQL queries. actor_ids - list of strings or integers The actor IDs to look up. The hook must return a dictionary that maps the incoming actor IDs to their full dictionary representation. Some plugins that implement social features may store the ID of the actor that performed an action - added a comment, bookmarked a table or similar - and then need a way to resolve those IDs into display-friendly actor dictionaries later on. The await datasette.actors_from_ids(actor_ids) internal method can be used to look up actors from their IDs. It will dispatch to the first plugin that implements this hook. Unlike other plugin hooks, this only uses the first implementation of the hook to return a result. You can expect users to only have a single plugin installed that implements this hook. If no plugin is installed, Datasette defaults to returning actors that are just {""id"": actor_id} . The hook can return a dictionary or an awaitable function that then returns a dictionary. This example implementation returns actors from a database table: from datasette import hookimpl @hookimpl def actors_from_ids(datasette, actor_ids): db = datasette.get_database(""actors"") async def inner(): sql = ""select id, name from actors where id in ({})"".format( "", "".join(""?"" for _ in actor_ids) ) actors = {} for row in (await db.execute(sql, actor_ids)).rows: actor = dict(row) actors[actor[""id""]] = actor return actors return inner The returned dictionary from this example looks like this: { ""1"": {""id"": ""1"", ""name"": ""Tony""}, ""2"": {""id"": ""2"", ""name"": ""Tina""}, } These IDs could be integers or strings, depending on how the actors used by the Datasette instance are configured. Example: datasette-remote-actors","[""Plugin hooks""]","[{""href"": ""https://github.com/datasette/datasette-remote-actors"", ""label"": ""datasette-remote-actors""}]" plugin_hooks:plugin-hook-actor-from-request,plugin_hooks,plugin-hook-actor-from-request,"actor_from_request(datasette, request)","datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) , or to execute SQL queries. request - Request object The current HTTP request. This is part of Datasette's authentication and permissions system . The function should attempt to authenticate an actor (either a user or an API actor of some sort) based on information in the request. If it cannot authenticate an actor, it should return None . Otherwise it should return a dictionary representing that actor. Here's an example that authenticates the actor based on an incoming API key: from datasette import hookimpl import secrets SECRET_KEY = ""this-is-a-secret"" @hookimpl def actor_from_request(datasette, request): authorization = ( request.headers.get(""authorization"") or """" ) expected = ""Bearer {}"".format(SECRET_KEY) if secrets.compare_digest(authorization, expected): return {""id"": ""bot""} If you install this in your plugins directory you can test it like this: curl -H 'Authorization: Bearer this-is-a-secret' http://localhost:8003/-/actor.json Instead of returning a dictionary, this function can return an awaitable function which itself returns either None or a dictionary. This is useful for authentication functions that need to make a database query - for example: from datasette import hookimpl @hookimpl def actor_from_request(datasette, request): async def inner(): token = request.args.get(""_token"") if not token: return None # Look up ?_token=xxx in sessions table result = await datasette.get_database().execute( ""select count(*) from sessions where token = ?"", [token], ) if result.first()[0]: return {""token"": token} else: return None return inner Examples: datasette-auth-tokens , datasette-auth-passwords","[""Plugin hooks""]","[{""href"": ""https://datasette.io/plugins/datasette-auth-tokens"", ""label"": ""datasette-auth-tokens""}, {""href"": ""https://datasette.io/plugins/datasette-auth-passwords"", ""label"": ""datasette-auth-passwords""}]" plugin_hooks:plugin-event-tracking,plugin_hooks,plugin-event-tracking,Event tracking,"Datasette includes an internal mechanism for tracking notable events. This can be used for analytics, but can also be used by plugins that want to listen out for when key events occur (such as a table being created) and take action in response. Plugins can register to receive events using the track_event plugin hook. They can also define their own events for other plugins to receive using the register_events() plugin hook , combined with calls to the datasette.track_event() internal method .","[""Plugin hooks""]",[] plugin_hooks:plugin-asgi-wrapper,plugin_hooks,plugin-asgi-wrapper,asgi_wrapper(datasette),"Return an ASGI middleware wrapper function that will be applied to the Datasette ASGI application. This is a very powerful hook. You can use it to manipulate the entire Datasette response, or even to configure new URL routes that will be handled by your own custom code. You can write your ASGI code directly against the low-level specification, or you can use the middleware utilities provided by an ASGI framework such as Starlette . This example plugin adds a x-databases HTTP header listing the currently attached databases: from datasette import hookimpl from functools import wraps @hookimpl def asgi_wrapper(datasette): def wrap_with_databases_header(app): @wraps(app) async def add_x_databases_header( scope, receive, send ): async def wrapped_send(event): if event[""type""] == ""http.response.start"": original_headers = ( event.get(""headers"") or [] ) event = { ""type"": event[""type""], ""status"": event[""status""], ""headers"": original_headers + [ [ b""x-databases"", "", "".join( datasette.databases.keys() ).encode(""utf-8""), ] ], } await send(event) await app(scope, receive, wrapped_send) return add_x_databases_header return wrap_with_databases_header Examples: datasette-cors , datasette-pyinstrument , datasette-total-page-time","[""Plugin hooks""]","[{""href"": ""https://asgi.readthedocs.io/"", ""label"": ""ASGI""}, {""href"": ""https://www.starlette.io/middleware/"", ""label"": ""Starlette""}, {""href"": ""https://datasette.io/plugins/datasette-cors"", ""label"": ""datasette-cors""}, {""href"": ""https://datasette.io/plugins/datasette-pyinstrument"", ""label"": ""datasette-pyinstrument""}, {""href"": ""https://datasette.io/plugins/datasette-total-page-time"", ""label"": ""datasette-total-page-time""}]" plugin_hooks:plugin-actions,plugin_hooks,plugin-actions,Action hooks,"Action hooks can be used to add items to the action menus that appear at the top of different pages within Datasette. Unlike menu_links() , actions which are displayed on every page, actions should only be relevant to the page the user is currently viewing. Each of these hooks should return return a list of {""href"": ""..."", ""label"": ""...""} menu items, with optional ""description"": ""..."" keys describing each action in more detail. They can alternatively return an async def awaitable function which, when called, returns a list of those menu items.","[""Plugin hooks""]",[] plugin_hooks:id1,plugin_hooks,id1,Plugin hooks,"Datasette plugins use plugin hooks to customize Datasette's behavior. These hooks are powered by the pluggy plugin system. Each plugin can implement one or more hooks using the @hookimpl decorator against a function named that matches one of the hooks documented on this page. When you implement a plugin hook you can accept any or all of the parameters that are documented as being passed to that hook. For example, you can implement the render_cell plugin hook like this even though the full documented hook signature is render_cell(row, value, column, table, database, datasette) : @hookimpl def render_cell(value, column): if column == ""stars"": return ""*"" * int(value) List of plugin hooks prepare_connection(conn, database, datasette) prepare_jinja2_environment(env, datasette) Page extras extra_template_vars(template, database, table, columns, view_name, request, datasette) extra_css_urls(template, database, table, columns, view_name, request, datasette) extra_js_urls(template, database, table, columns, view_name, request, datasette) extra_body_script(template, database, table, columns, view_name, request, datasette) publish_subcommand(publish) render_cell(row, value, column, table, database, datasette, request) register_output_renderer(datasette) register_routes(datasette) register_commands(cli) register_facet_classes() register_permissions(datasette) asgi_wrapper(datasette) startup(datasette) canned_queries(datasette, database, actor) actor_from_request(datasette, request) actors_from_ids(datasette, actor_ids) jinja2_environment_from_request(datasette, request, env) filters_from_request(request, database, table, datasette) permission_allowed(datasette, actor, action, resource) register_magic_parameters(datasette) forbidden(datasette, request, message) handle_exception(datasette, request, exception) skip_csrf(datasette, scope) get_metadata(datasette, key, database, table) menu_links(datasette, actor, request) Action hooks table_actions(datasette, actor, database, table, request) view_actions(datasette, actor, database, view, request) query_actions(datasette, actor, database, query_name, request, sql, params) row_actions(datasette, actor, request, database, table, row) database_actions(datasette, actor, database, request) homepage_actions(datasette, actor, request) Template slots top_homepage(datasette, request) top_database(datasette, request, database) top_table(datasette, request, database, table) top_row(datasette, request, database, table, row) top_query(datasette, request, database, sql) top_canned_query(datasette, request, database, query_name) Event tracking track_event(datasette, event) register_events(datasette)",[],"[{""href"": ""https://pluggy.readthedocs.io/"", ""label"": ""pluggy""}]"