home / docs / sections

sections

24 rows where breadcrumbs contains "Plugin hooks" and references = "[]"

✎ View and edit SQL

This data as json, CSV (advanced)

Suggested facets: breadcrumbs, breadcrumbs (array)

id ▼ page ref title content breadcrumbs references
plugin_hooks:allow-alice-to-view-a-specific-table plugin_hooks allow-alice-to-view-a-specific-table Allow Alice to view a specific table This plugin grants the actor with id == "alice" permission to perform the view-table action against the sales table inside the accounting database. from datasette import hookimpl from datasette.permissions import PermissionSQL @hookimpl def permission_resources_sql(datasette, actor, action): if action != "view-table": return None if not actor or actor.get("id") != "alice": return None return PermissionSQL( sql=""" SELECT 'accounting' AS parent, 'sales' AS child, 1 AS allow, 'alice can view accounting/sales' AS reason """, ) ["Plugin hooks", "permission_resources_sql(datasette, actor, action)", "Permission plugin examples"] []
plugin_hooks:default-deny-with-an-exception plugin_hooks default-deny-with-an-exception Default deny with an exception Combine a root-level deny with a specific table allow for trusted users. The resolver will automatically apply the most specific rule. from datasette import hookimpl from datasette.permissions import PermissionSQL TRUSTED = {"alice", "bob"} @hookimpl def permission_resources_sql(datasette, actor, action): if action != "view-table": return None actor_id = (actor or {}).get("id") if actor_id not in TRUSTED: return PermissionSQL( sql=""" SELECT NULL AS parent, NULL AS child, 0 AS allow, 'default deny view-table' AS reason """, ) return PermissionSQL( sql=""" SELECT NULL AS parent, NULL AS child, 0 AS allow, 'default deny view-table' AS reason UNION ALL SELECT 'reports' AS parent, 'daily_metrics' AS child, 1 AS allow, 'trusted user access' AS reason """, params={"actor_id": actor_id}, ) The UNION ALL ensures the deny rule is always present, while the second row adds the exception for trusted users. ["Plugin hooks", "permission_resources_sql(datasette, actor, action)", "Permission plugin examples"] []
plugin_hooks:permission-plugin-examples plugin_hooks permission-plugin-examples Permission plugin examples These snippets show how to use the new permission_resources_sql hook to contribute rows to the action-based permission resolver. Each hook receives the current actor dictionary (or None ) and must return None or an instance or list of datasette.permissions.PermissionSQL (or a coroutine that resolves to that). ["Plugin hooks", "permission_resources_sql(datasette, actor, action)"] []
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: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-hook-forbidden plugin_hooks plugin-hook-forbidden forbidden(datasette, request, message) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) , or to render templates or execute SQL queries. request - Request object The current HTTP request. message - string A message hinting at why the request was forbidden. Plugins can use this to customize how Datasette responds when a 403 Forbidden error occurs - usually because a page failed a permission check, see Permissions . If a plugin hook wishes to react to the error, it should return a Response object . This example returns a redirect to a /-/login page: from datasette import hookimpl from urllib.parse import urlencode @hookimpl def forbidden(request, message): return Response.redirect( "/-/login?=" + urlencode({"message": message}) ) The function can alternatively return an awaitable function if it needs to make any asynchronous method calls. This example renders a template: from datasette import hookimpl, Response @hookimpl def forbidden(datasette): async def inner(): return Response.html( await datasette.render_template( "render_message.html", request=request ) ) return inner ["Plugin hooks"] []
plugin_hooks:plugin-hook-homepage-actions plugin_hooks plugin-hook-homepage-actions homepage_actions(datasette, actor, 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. actor - dictionary or None The currently authenticated actor . request - Request object The current HTTP request. Populates an actions menu on the top-level index homepage of the Datasette instance. This example adds a link an imagined tool for editing the homepage, only for signed in users: from datasette import hookimpl @hookimpl def homepage_actions(datasette, actor): if actor: return [ { "href": datasette.urls.path( "/-/customize-homepage" ), "label": "Customize homepage", } ] ["Plugin hooks", "Action hooks"] []
plugin_hooks:plugin-hook-permission-resources-sql plugin_hooks plugin-hook-permission-resources-sql permission_resources_sql(datasette, actor, action) datasette - Datasette class Access to the Datasette instance. actor - dictionary or None The current actor dictionary. None for anonymous requests. action - string The permission action being evaluated. Examples include "view-table" or "insert-row" . Return value A datasette.permissions.PermissionSQL object, None or an iterable of PermissionSQL objects. Datasette's action-based permission resolver calls this hook to gather SQL rows describing which resources an actor may access ( allow = 1 ) or should be denied ( allow = 0 ) for a specific action. Each SQL snippet should return parent , child , allow and reason columns. Parameter naming convention: Plugin parameters in PermissionSQL.params should use unique names to avoid conflicts with other plugins. The recommended convention is to prefix parameters with your plugin's source name (e.g., myplugin_user_id ). The system reserves these parameter names: :actor , :actor_id , :action , and :filter_parent . You can also use return PermissionSQL.allow(reason="reason goes here") or PermissionSQL.deny(reason="reason goes here") as shortcuts for simple root-level allow or deny rules. These will create SQL snippets that look like this: SELECT NULL AS parent, NULL AS child, 1 AS allow, 'reason goes here' AS reason Or 0 AS allow for denies. ["Plugin hooks"] []
plugin_hooks:plugin-hook-register-events plugin_hooks plugin-hook-register-events register_events(datasette) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . This hook should return a list of Event subclasses that represent custom events that the plugin might send to the datasette.track_event() method. This example registers event subclasses for ban-user and unban-user events: from dataclasses import dataclass from datasette import hookimpl, Event @dataclass class BanUserEvent(Event): name = "ban-user" user: dict @dataclass class UnbanUserEvent(Event): name = "unban-user" user: dict @hookimpl def register_events(): return [BanUserEvent, UnbanUserEvent] The plugin can then call datasette.track_event(...) to send a ban-user event: await datasette.track_event( BanUserEvent(user={"id": 1, "username": "cleverbot"}) ) ["Plugin hooks", "Event tracking"] []
plugin_hooks:plugin-hook-register-magic-parameters plugin_hooks plugin-hook-register-magic-parameters register_magic_parameters(datasette) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . Magic parameters can be used to add automatic parameters to canned queries . This plugin hook allows additional magic parameters to be defined by plugins. Magic parameters all take this format: _prefix_rest_of_parameter . The prefix indicates which magic parameter function should be called - the rest of the parameter is passed as an argument to that function. To register a new function, return it as a tuple of (string prefix, function) from this hook. The function you register should take two arguments: key and request , where key is the rest_of_parameter portion of the parameter and request is the current Request object . This example registers two new magic parameters: :_request_http_version returning the HTTP version of the current request, and :_uuid_new which returns a new UUID. It also registers an :_asynclookup_key parameter, demonstrating that these functions can be asynchronous: from datasette import hookimpl from uuid import uuid4 def uuid(key, request): if key == "new": return str(uuid4()) else: raise KeyError def request(key, request): if key == "http_version": return request.scope["http_version"] else: raise KeyError async def asynclookup(key, request): return await do_something_async(key) @hookimpl def register_magic_parameters(datasette): return [ ("request", request), ("uuid", uuid), ("asynclookup", asynclookup), ] ["Plugin hooks"] []
plugin_hooks:plugin-hook-top-canned-query plugin_hooks plugin-hook-top-canned-query top_canned_query(datasette, request, database, query_name) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . request - Request object The current HTTP request. database - string The name of the database. query_name - string The name of the canned query. Returns HTML to be displayed at the top of the canned query page. ["Plugin hooks", "Template slots"] []
plugin_hooks:plugin-hook-top-database plugin_hooks plugin-hook-top-database top_database(datasette, request, database) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . request - Request object The current HTTP request. database - string The name of the database. Returns HTML to be displayed at the top of the database page. ["Plugin hooks", "Template slots"] []
plugin_hooks:plugin-hook-top-homepage plugin_hooks plugin-hook-top-homepage top_homepage(datasette, request) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . request - Request object The current HTTP request. Returns HTML to be displayed at the top of the Datasette homepage. ["Plugin hooks", "Template slots"] []
plugin_hooks:plugin-hook-top-query plugin_hooks plugin-hook-top-query top_query(datasette, request, database, sql) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . request - Request object The current HTTP request. database - string The name of the database. sql - string The SQL query. Returns HTML to be displayed at the top of the query results page. ["Plugin hooks", "Template slots"] []
plugin_hooks:plugin-hook-top-row plugin_hooks plugin-hook-top-row top_row(datasette, request, database, table, row) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . request - Request object The current HTTP request. database - string The name of the database. table - string The name of the table. row - sqlite.Row The SQLite row object being displayed. Returns HTML to be displayed at the top of the row page. ["Plugin hooks", "Template slots"] []
plugin_hooks:plugin-hook-top-table plugin_hooks plugin-hook-top-table top_table(datasette, request, database, table) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . request - Request object The current HTTP request. database - string The name of the database. table - string The name of the table. Returns HTML to be displayed at the top of the table page. ["Plugin hooks", "Template slots"] []
plugin_hooks:plugin-hook-view-actions plugin_hooks plugin-hook-view-actions view_actions(datasette, actor, database, view, 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. actor - dictionary or None The currently authenticated actor . database - string The name of the database. view - string The name of the SQL view. request - Request object or None The current HTTP request. This can be None if the request object is not available. Like table_actions(datasette, actor, database, table, request) but for SQL views. ["Plugin hooks", "Action hooks"] []
plugin_hooks:plugin-hook-write-wrapper plugin_hooks plugin-hook-write-wrapper write_wrapper(datasette, database, request, transaction) datasette - Datasette class You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) . database - string The name of the database being written to. request - Request object or None The HTTP request that triggered this write, if available. This will be None for writes that do not originate from an HTTP request (e.g. writes triggered by plugins during startup). transaction - bool True if the write will be wrapped in a database transaction. Return a generator function that accepts a conn argument (a SQLite connection object) and optionally a track_event argument. The generator should yield exactly once. Code before the yield runs before the write function executes; code after the yield runs after it completes. The result of the write function is sent back through the yield , so you can capture it with result = yield . If the write function raises an exception, it is thrown into the generator so you can handle it with a try / except around the yield . If your generator accepts track_event , you can call track_event(event) to queue an event that will be dispatched via datasette.track_event() after the write commits successfully. Events are discarded if the write raises an exception. Return None to skip wrapping for this particular write. This example logs every write operation: from datasette import hookimpl @hookimpl def write_wrapper(datasette, database, req… ["Plugin hooks"] []
plugin_hooks:plugin-page-extras plugin_hooks plugin-page-extras Page extras These plugin hooks can be used to affect the way HTML pages for different Datasette interfaces are rendered. ["Plugin hooks"] []
plugin_hooks:plugin-register-actions plugin_hooks plugin-register-actions register_actions(datasette) If your plugin needs to register actions that can be checked with Datasette's new resource-based permission system, return a list of those actions from this hook. Actions define what operations can be performed on resources (like viewing a table, executing SQL, or custom plugin actions). from datasette import hookimpl from datasette.permissions import Action, Resource class DocumentCollectionResource(Resource): """A collection of documents.""" name = "document-collection" parent_class = None def __init__(self, collection: str): super().__init__(parent=collection, child=None) @classmethod async def resources_sql( cls, datasette, actor=None ) -> str: return """ SELECT collection_name AS parent, NULL AS child FROM document_collections """ class DocumentResource(Resource): """A document in a collection.""" name = "document" parent_class = DocumentCollectionResource def __init__(self, collection: str, document: str): super().__init__(parent=collection, child=document) @classmethod async def resources_sql( cls, datasette, actor=None ) -> str: return """ SELECT collection_name AS parent, document_id AS child FROM documents """ @hookimpl def register_actions(datasette): return [ Action( name="list-documents", abbr="ld", description="List documents in a collection", resource_class=DocumentCollectionResource, ), Action( name="view-document", abbr="vdoc", description="View document", resource_class=DocumentResource, ), Action( name="edit-document", abbr="edoc", description="Edit document", resource_class=DocumentResource, ), ] The fields of the Action dataclass are as follows: … ["Plugin hooks"] []
plugin_hooks:plugin-register-column-types plugin_hooks plugin-register-column-types register_column_types(datasette) Return a list of ColumnType subclasses (not instances) to register custom column types. Column types define how values in specific columns are rendered, validated, and transformed. from datasette import hookimpl from datasette.column_types import ColumnType, SQLiteType import markupsafe class ColorColumnType(ColumnType): name = "color" description = "CSS color value" sqlite_types = (SQLiteType.TEXT,) async def render_cell( self, value, column, table, database, datasette, request, ): if value: return markupsafe.Markup( '<span style="background-color: {color}">' "{color}</span>" ).format(color=markupsafe.escape(value)) return None async def validate(self, value, datasette): if value and not value.startswith("#"): return "Color must start with #" return None async def transform_value(self, value, datasette): # Normalize to uppercase if isinstance(value, str): return value.upper() return value @hookimpl def register_column_types(datasette): return [ColorColumnType] Each ColumnType subclass must define the following class attributes: name - string Unique identifier for the column type, e.g. "color" . Must be unique across all plugins. description - string Human-readable label, e.g. "CSS color value" . sqlite_types - tuple of SQLiteType values, optional Restrict assignments of this column type to columns with matching SQLite types, e.g. (SQLiteType.TEXT,) . If omitted, the column type can be assigned… ["Plugin hooks"] []
plugin_hooks:plugin-resources-sql plugin_hooks plugin-resources-sql The The resources_sql() classmethod returns a SQL query that lists all resources of that type that exist in the system. It can be async because Datasette calls it with await , and it receives the current datasette instance plus an optional actor argument. This query is used by Datasette to efficiently check permissions across multiple resources at once. When a user requests a list of resources (like tables, documents, or other entities), Datasette uses this SQL to: Get all resources of this type from your data catalog Combine it with permission rules from the permission_resources_sql hook Use SQL joins and filtering to determine which resources the actor can access Return only the permitted resources The SQL query must return exactly two columns: parent - The parent identifier (e.g., database name, collection name), or NULL for top-level resources child - The child identifier (e.g., table name, document ID), or NULL for parent-only resources For example, if you're building a document management plugin with collections and documents stored in a documents table, your resources_sql() might look like: @classmethod async def resources_sql(cls, datasette, actor=None) -> str: return """ SELECT collection_name AS parent, document_id AS child FROM documents """ This tells Datasette "here's how to find all documents in the system - look in the documents table and get the collection name and document ID for each … ["Plugin hooks", "register_actions(datasette)"] []
plugin_hooks:read-permissions-from-a-custom-table plugin_hooks read-permissions-from-a-custom-table Read permissions from a custom table This example stores grants in an internal table called permission_grants with columns (actor_id, action, parent, child, allow, reason) . from datasette import hookimpl from datasette.permissions import PermissionSQL @hookimpl def permission_resources_sql(datasette, actor, action): if not actor: return None return PermissionSQL( sql=""" SELECT parent, child, allow, COALESCE(reason, 'permission_grants table') AS reason FROM permission_grants WHERE actor_id = :grants_actor_id AND action = :grants_action """, params={ "grants_actor_id": actor.get("id"), "grants_action": action, }, ) ["Plugin hooks", "permission_resources_sql(datasette, actor, action)", "Permission plugin examples"] []
plugin_hooks:restrict-execute-sql-to-a-database-prefix plugin_hooks restrict-execute-sql-to-a-database-prefix Restrict execute-sql to a database prefix Only allow execute-sql against databases whose name begins with analytics_ . This shows how to use parameters that the permission resolver will pass through to the SQL snippet. from datasette import hookimpl from datasette.permissions import PermissionSQL @hookimpl def permission_resources_sql(datasette, actor, action): if action != "execute-sql": return None return PermissionSQL( sql=""" SELECT parent, NULL AS child, 1 AS allow, 'execute-sql allowed for analytics_*' AS reason FROM catalog_databases WHERE database_name LIKE :analytics_prefix """, params={ "analytics_prefix": "analytics_%", }, ) ["Plugin hooks", "permission_resources_sql(datasette, actor, action)", "Permission plugin examples"] []

Advanced export

JSON shape: default, array, newline-delimited, object

CSV options:

CREATE TABLE [sections] (
   [id] TEXT PRIMARY KEY,
   [page] TEXT,
   [ref] TEXT,
   [title] TEXT,
   [content] TEXT,
   [breadcrumbs] TEXT,
   [references] TEXT
);
Powered by Datasette · Queries took 1.2ms