id,page,ref,title,content,breadcrumbs,references authentication:actions,authentication,actions,Built-in actions,"This section lists all of the permission checks that are carried out by Datasette core, along with the resource if it was passed.","[""Authentication and permissions""]",[] authentication:actions-alter-table,authentication,actions-alter-table,alter-table,"Actor is allowed to alter a database table. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the table (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-create-table,authentication,actions-create-table,create-table,"Actor is allowed to create a database table. resource - datasette.resources.DatabaseResource(database) database is the name of the database (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-create-view,authentication,actions-create-view,create-view,"Actor is allowed to create a database view. resource - datasette.resources.DatabaseResource(database) database is the name of the database (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-debug-menu,authentication,actions-debug-menu,debug-menu,Controls if the various debug pages are displayed in the jump menu.,"[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-delete-query,authentication,actions-delete-query,delete-query,"Actor is allowed to delete a stored query. resource - datasette.resources.QueryResource(database, query) database is the name of the database (string) query is the name of the query (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-delete-row,authentication,actions-delete-row,delete-row,"Actor is allowed to delete rows from a table. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the table (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-drop-table,authentication,actions-drop-table,drop-table,"Actor is allowed to drop a database table. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the table (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-drop-view,authentication,actions-drop-view,drop-view,"Actor is allowed to drop a database view. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the view (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-execute-write-sql,authentication,actions-execute-write-sql,execute-write-sql,"Actor is allowed to run arbitrary writable SQL queries against a specific database using the write SQL queries page , subject to table-level write permissions such as insert-row , update-row and delete-row . SQL functions are allowed and are not separately restricted by Datasette permissions. resource - datasette.resources.DatabaseResource(database) database is the name of the database (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-insert-row,authentication,actions-insert-row,insert-row,"Actor is allowed to insert rows into a table. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the table (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-permissions-debug,authentication,actions-permissions-debug,permissions-debug,Actor is allowed to view the /-/permissions debug tools.,"[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-set-column-type,authentication,actions-set-column-type,set-column-type,"Actor is allowed to set assigned column types for columns in a table. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the table (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-store-query,authentication,actions-store-query,store-query,"Actor is allowed to create stored queries against a database. resource - datasette.resources.DatabaseResource(database) database is the name of the database (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-update-query,authentication,actions-update-query,update-query,"Actor is allowed to update a stored query. resource - datasette.resources.QueryResource(database, query) database is the name of the database (string) query is the name of the query (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:actions-update-row,authentication,actions-update-row,update-row,"Actor is allowed to update rows in a table. resource - datasette.resources.TableResource(database, table) database is the name of the database (string) table is the name of the table (string)","[""Authentication and permissions"", ""Built-in actions""]",[] authentication:allowedresourcesview,authentication,allowedresourcesview,Allowed resources view,"The /-/allowed endpoint displays resources that the current actor can access for a specified action . This endpoint provides an interactive HTML form interface. Add .json to the URL path (e.g. /-/allowed.json ) to get the raw JSON response instead. Pass ?action=view-table (or another action) to select the action. Optional parent= and child= query parameters can narrow the results to a specific database/table pair. Results are paginated: ?_size= sets the page size (default 50, maximum 200, max for the maximum) and ?_page= selects a page. This endpoint is publicly accessible to help users understand their own permissions. The potentially sensitive reason field is only shown to users with the permissions-debug permission - it shows the plugins and explanatory reasons that were responsible for each decision.","[""Authentication and permissions"", ""Permissions debug tools""]",[] authentication:authentication,authentication,authentication,Authentication and permissions,"Datasette doesn't require authentication by default. Any visitor to a Datasette instance can explore the full data and execute read-only SQL queries. Datasette can be configured to only allow authenticated users, or to control which databases, tables, and queries can be accessed by the public or by specific users. Datasette's plugin system can be used to add many different styles of authentication, such as user accounts, single sign-on or API keys.",[],[] authentication:authentication-actor,authentication,authentication-actor,Actors,"Through plugins, Datasette can support both authenticated users (with cookies) and authenticated API clients (via authentication tokens). The word ""actor"" is used to cover both of these cases. Every request to Datasette has an associated actor value, available in the code as request.actor . This can be None for unauthenticated requests, or a JSON compatible Python dictionary for authenticated users or API clients. The actor dictionary can be any shape - the design of that data structure is left up to the plugins. Actors should always include a unique ""id"" string, as demonstrated by the ""root"" actor below. Plugins can use the actor_from_request(datasette, request) hook to implement custom logic for authenticating an actor based on the incoming HTTP request.","[""Authentication and permissions""]",[] authentication:authentication-actor-display,authentication,authentication-actor-display,How actors are displayed,"In a number of places - such as the navigation menu and the /-/logout page - Datasette needs to display a short label representing the currently authenticated actor. To decide what to show, Datasette looks through the following keys in the actor dictionary and uses the value of the first one that is present and not empty: display name username login id If none of those keys have a value the actor dictionary is displayed as a string instead.","[""Authentication and permissions"", ""Actors""]",[] authentication:authentication-actor-matches-allow,authentication,authentication-actor-matches-allow,actor_matches_allow(),"Plugins that wish to implement this same ""allow"" block permissions scheme can take advantage of the datasette.utils.actor_matches_allow(actor, allow) function: from datasette.utils import actor_matches_allow actor_matches_allow({""id"": ""root""}, {""id"": ""*""}) # returns True The currently authenticated actor is made available to plugins as request.actor .","[""Authentication and permissions""]",[] authentication:authentication-cli-create-token,authentication,authentication-cli-create-token,datasette create-token,"You can also create tokens on the command line using the datasette create-token command. This command takes one required argument - the ID of the actor to be associated with the created token. You can specify a -e/--expires-after option in seconds. If omitted, the token will never expire. The command will sign the token using the DATASETTE_SECRET environment variable, if available. You can also pass the secret using the --secret option. This means you can run the command locally to create tokens for use with a deployed Datasette instance, provided you know that instance's secret. To create a token for the root actor that will expire in one hour: datasette create-token root --expires-after 3600 To create a token that never expires using a specific secret: datasette create-token root --secret my-secret-goes-here","[""Authentication and permissions"", ""API Tokens""]",[] authentication:authentication-cli-create-token-restrict,authentication,authentication-cli-create-token-restrict,Restricting the actions that a token can perform,"Tokens created using datasette create-token ACTOR_ID will inherit all of the permissions of the actor that they are associated with. You can pass additional options to create tokens that are restricted to a subset of that actor's permissions. To restrict the token to just specific permissions against all available databases, use the --all option: datasette create-token root --all insert-row --all update-row This option can be passed as many times as you like. In the above example the token will only be allowed to insert and update rows. You can also restrict permissions such that they can only be used within specific databases: datasette create-token root --database mydatabase insert-row The resulting token will only be able to insert rows, and only to tables in the mydatabase database. Finally, you can restrict permissions to individual resources - tables, SQL views and named queries - within a specific database: datasette create-token root --resource mydatabase mytable insert-row These options have short versions: -a for --all , -d for --database and -r for --resource . You can add --debug to see a JSON representation of the token that has been created. Here's a full example: datasette create-token root \ --secret mysecret \ --all view-instance \ --all view-table \ --database docs view-query \ --resource docs documents insert-row \ --resource docs documents update-row \ --debug This example outputs the following: dstok_.eJxFizEKgDAMRe_y5w4qYrFXERGxDkVsMI0uxbubdjFL8l_ez1jhwEQCA6Fjjxp90qtkuHawzdjYrh8MFobLxZ_wBH0_gtnAF-hpS5VfmF8D_lnd97lHqUJgLd6sls4H1qwlhA.nH_7RecYHj5qSzvjhMU95iy0Xlc Decoded: { ""a"": ""root"", ""token"": ""dstok"", ""t"": 1670907246, ""_r"": { ""a"": [ ""vi"", ""vt"" ], ""d"": { ""docs"": [ ""vq"" ] }, ""r"": { ""docs"": { ""documents"": [ ""ir"", ""ur"" ] } } } } Restrictions act as an allowlist layered on top of the actor's existing permissions. They can only remove access the actor would otherwise have—they cannot grant new access. If the underlying actor is denied by allow rules in datasette.yaml or by a plugin, a token that lists that resource in its ""_r"" section will still be denied. To create tokens with restrictions in Python code, use the TokenRestrictions builder and pass it to datasette.create_token() .","[""Authentication and permissions"", ""API Tokens"", ""datasette create-token""]",[] authentication:authentication-default-deny,authentication,authentication-default-deny,Denying all permissions by default,"By default, Datasette allows unauthenticated access to view databases, tables, and execute SQL queries. You may want to run Datasette in a mode where all access is denied by default, and you explicitly grant permissions only to authenticated users, either using the --root mechanism or through configuration file rules or plugins. Use the --default-deny command-line option to run Datasette in this mode: datasette --default-deny data.db --root With --default-deny enabled: Anonymous users are denied access to view the instance, databases, tables, and queries Authenticated users are also denied access unless they're explicitly granted permissions The root user (when using --root ) still has access to everything You can grant permissions using configuration file rules or plugins For example, to allow only a specific user to access your instance: datasette --default-deny data.db --config datasette.yaml Where datasette.yaml contains: allow: id: alice This configuration will deny access to everyone except the user with id of alice .","[""Authentication and permissions"", ""Permissions""]",[] authentication:authentication-ds-actor,authentication,authentication-ds-actor,The ds_actor cookie,"Datasette includes a default authentication plugin which looks for a signed ds_actor cookie containing a JSON actor dictionary. This is how the root actor mechanism works. Authentication plugins can set signed ds_actor cookies themselves like so: response = Response.redirect(""/"") datasette.set_actor_cookie(response, {""id"": ""cleopaws""}) The shape of data encoded in the cookie is as follows: { ""a"": { ""id"": ""cleopaws"" } } To implement logout in a plugin, use the delete_actor_cookie() method: response = Response.redirect(""/"") datasette.delete_actor_cookie(response)","[""Authentication and permissions""]",[] authentication:authentication-ds-actor-expiry,authentication,authentication-ds-actor-expiry,Including an expiry time,"ds_actor cookies can optionally include a signed expiry timestamp, after which the cookies will no longer be valid. Authentication plugins may chose to use this mechanism to limit the lifetime of the cookie. For example, if a plugin implements single-sign-on against another source it may decide to set short-lived cookies so that if the user is removed from the SSO system their existing Datasette cookies will stop working shortly afterwards. To include an expiry pass expire_after= to datasette.set_actor_cookie() with a number of seconds. For example, to expire in 24 hours: response = Response.redirect(""/"") datasette.set_actor_cookie( response, {""id"": ""cleopaws""}, expire_after=60 * 60 * 24 ) The resulting cookie will encode data that looks something like this: { ""a"": { ""id"": ""cleopaws"" }, ""e"": ""1jjSji"" }","[""Authentication and permissions"", ""The ds_actor cookie""]",[] authentication:authentication-permissions,authentication,authentication-permissions,Permissions,"The key question the permissions system answers is this: Is this actor allowed to perform this action , optionally against this particular resource ? Every permission decision can be understood in terms of those three values. Datasette implements the decisions using SQL, but you do not need to understand the generated SQL to configure or debug permissions. Actors are described above . An action is a string describing the action the actor would like to perform. A full list is provided below - examples include view-table and execute-sql . A resource is the item the actor wishes to interact with - for example a specific database or table. Some actions, such as permissions-debug , are not associated with a particular resource. Datasette's built-in view actions ( view-database , view-table etc) are allowed by Datasette's default configuration: unless you configure additional permission rules unauthenticated users will be allowed to access content. Other actions, including those introduced by plugins, will default to deny .","[""Authentication and permissions""]",[] authentication:authentication-permissions-config,authentication,authentication-permissions-config,Access permissions in ,"There are two ways to configure permissions using datasette.yaml (or datasette.json ). For simple visibility permissions you can use ""allow"" blocks in the root, database, table and query sections. For other permissions you can use a ""permissions"" block, described in the next section . You can limit who is allowed to view different parts of your Datasette instance using ""allow"" keys in your Configuration . You can control the following: Access to the entire Datasette instance Access to specific databases Access to specific tables and views Access to specific queries If a user has permission to view a table they will be able to view that table, independent of if they have permission to view the database or instance that the table exists within.","[""Authentication and permissions""]",[] authentication:authentication-permissions-database,authentication,authentication-permissions-database,Access to specific databases,"To limit access to a specific private.db database to just authenticated users, use the ""allow"" block like this: [[[cog config_example(cog, """""" databases: private: allow: id: ""*"" """""") ]]] [[[end]]]","[""Authentication and permissions"", ""Access permissions in ""]",[] authentication:authentication-permissions-explained,authentication,authentication-permissions-explained,How permissions are resolved,"Permission rules describe an effect ( allow or deny ) at one of three levels: resource A specific child resource, such as the analytics/sales table. parent A parent resource, such as the analytics database. A parent rule also applies to its child resources. global Every resource for that action. Datasette resolves matching rules from most specific to least specific: Resource rules take precedence over parent and global rules. Parent rules take precedence over global rules. If both allow and deny rules match at the same level, deny takes precedence. If no rule matches, access is denied. This means a resource-level allow can provide an exception to a parent-level deny. It also means that two plugins which disagree at the same level resolve to deny. Permission rule examples Matching rules Result Explanation Global allow Allow The global rule is the most specific matching rule. Global allow, parent deny Deny The parent rule is more specific. Parent deny, resource allow Allow The resource rule is more specific. Resource allow and resource deny Deny Deny takes precedence at the same level. No matching rules Deny Permissions default to deny when no rule applies. The built-in public defaults are global allow rules for actions such as view-instance , view-database and view-table . They follow the same precedence rules as configuration and plugin rules. The --default-deny option prevents Datasette from contributing those default allow rules. Datasette performs checks using await .allowed(*, action, resource, actor=None) , which accepts keyword arguments for action , resource and an optional actor . resource should be an instance of the appropriate Resource subclass from datasette.resources —for example InstanceResource() , DatabaseResource(database=""... )`` or TableResource(database=""..."", table=""..."") . This defaults to InstanceResource() if not specified. When a check runs Datasette gathers allow/deny rules from multiple sources and compiles them into a SQL query. The resulting query describes all of the resources an actor may access for that action, together with the reasons those resources were allowed or denied. The combined sources are: allow blocks configured in datasette.yaml . Actor restrictions encoded into the actor dictionary or API token. The ""root"" user rule when --root (or Datasette.root_enabled ) is active. This is a global allow rule, so a more specific configuration deny can override it. Any additional SQL provided by plugins implementing permission_resources_sql(datasette, actor, action) . Actor restrictions are applied after the allow/deny rules. They act as an additional allowlist: a restriction can remove access but cannot grant access that the actor did not already have. See Restricting the actions that a token can perform . Some actions have dependencies on other actions. These are evaluated as an AND condition. For example, execute-sql also requires view-database : both decisions must be allowed for the final result to be allowed.","[""Authentication and permissions"", ""Permissions""]",[] authentication:authentication-permissions-other,authentication,authentication-permissions-other,Other permissions in ,"For all other permissions, you can use one or more ""permissions"" blocks in your datasette.yaml configuration file. To grant access to the permissions debug tool to all signed in users, you can grant permissions-debug to any actor with an id matching the wildcard * by adding this a the root of your configuration: [[[cog config_example(cog, """""" permissions: debug-menu: id: '*' """""") ]]] [[[end]]] To grant create-table to the user with id of editor for the docs database: [[[cog config_example(cog, """""" databases: docs: permissions: create-table: id: editor """""") ]]] [[[end]]] Other table-scoped write permissions, including set-column-type , can be configured in the same place. And for insert-row against the reports table in that docs database: [[[cog config_example(cog, """""" databases: docs: tables: reports: permissions: insert-row: id: editor """""") ]]] [[[end]]] The permissions debug tool can be useful for helping test permissions that you have configured in this way.","[""Authentication and permissions""]",[] authentication:authentication-permissions-query,authentication,authentication-permissions-query,Access to specific queries,"Queries allow you to configure named SQL queries in your datasette.yaml that can be executed by users. These queries can be set up to both read and write to the database, so controlling who can execute them can be important. To limit access to the add_name query in your dogs.db database to just the root user : [[[cog config_example(cog, """""" databases: dogs: queries: add_name: sql: INSERT INTO names (name) VALUES (:name) write: true allow: id: - root """""") ]]] [[[end]]]","[""Authentication and permissions"", ""Access permissions in ""]",[] authentication:createtokenview,authentication,createtokenview,API Tokens,"Datasette includes a default mechanism for generating API tokens that can be used to authenticate requests. Authenticated users can create new API tokens using a form on the /-/create-token page. Tokens created in this way can be further restricted to only allow access to specific actions, or to limit those actions to specific databases, tables or queries. Created tokens can then be passed in the Authorization: Bearer $token header of HTTP requests to Datasette. A token created by a user will include that user's ""id"" in the token payload, so any permissions granted to that user based on their ID can be made available to the token as well. When one of these a token accompanies a request, the actor for that request will have the following shape: { ""id"": ""user_id"", ""token"": ""dstok"", ""token_expires"": 1667717426 } The ""id"" field duplicates the ID of the actor who first created the token. The ""token"" field identifies that this actor was authenticated using a Datasette signed token ( dstok ). The ""token_expires"" field, if present, indicates that the token will expire after that integer timestamp. The /-/create-token page cannot be accessed by actors that are authenticated with a ""token"": ""some-value"" property. This is to prevent API tokens from being used to create more tokens. Datasette plugins that implement their own form of API token authentication should follow this convention. If a request presents a token that a token handler recognizes but rejects - an invalid signature, a malformed payload or an expired token - Datasette responds with a 401 status, the standard JSON error format and a WWW-Authenticate: Bearer error=""invalid_token"" header. This means API clients can distinguish ""your token needs to be renewed"" ( 401 ) from ""your token does not grant this permission"" ( 403 ). A Bearer token that no registered handler recognizes at all is ignored, since it may be intended for an authentication plugin. You can disable the signed token feature entirely using the allow_signed_tokens setting. Requests presenting a dstok_ token while the feature is disabled receive a 401 .","[""Authentication and permissions""]",[] authentication:logoutview,authentication,logoutview,The /-/logout page,The page at /-/logout provides the ability to log out of a ds_actor cookie authentication session.,"[""Authentication and permissions"", ""The ds_actor cookie""]",[] authentication:permissioncheckview,authentication,permissioncheckview,Permission check view,"The /-/check endpoint evaluates and explains a single actor, action and resource decision. The explanation includes: Every matching allow and deny rule, with its source and reason. The winning resource, parent or global scope. Rules ignored because a more specific rule matched, or because a deny won at the same scope. Actor restriction allowlists that included or excluded the resource. Additional actions required by the requested action. An explicit default-deny explanation when no rule matched. This endpoint provides an interactive HTML form interface. Add .json to the URL path (e.g. /-/check.json?action=view-instance ) to get the raw JSON response instead. Pass ?action= to specify the action to check, and optional ?parent= and ?child= parameters to specify the resource. The interactive form also accepts actor JSON, allowing a hypothetical actor to be tested without signing in as that actor. The JSON endpoint accepts the same value using the actor query string parameter. Use actor=null to represent an anonymous actor. This endpoint requires the permissions-debug permission. The hypothetical actor is used only for the decision being explained; access to the debug tool is checked against the actor who is actually signed in.","[""Authentication and permissions"", ""Permissions debug tools""]",[] authentication:permissionrulesview,authentication,permissionrulesview,Permission rules view,"The /-/rules endpoint displays all permission rules (both allow and deny) for each candidate resource for the requested action. This endpoint provides an interactive HTML form interface. Add .json to the URL path (e.g. /-/rules.json?action=view-table ) to get the raw JSON response instead. Pass ?action= as a query parameter to specify which action to check. The ?_size= and ?_page= pagination parameters work the same as on /-/allowed . This endpoint requires the permissions-debug permission.","[""Authentication and permissions"", ""Permissions debug tools""]",[] authentication:permissions-plugins,authentication,permissions-plugins,Checking permissions in plugins,"Datasette plugins can check if an actor has permission to perform an action using await .allowed(*, action, resource, actor=None) —for example: from datasette.resources import TableResource can_edit = await datasette.allowed( action=""update-row"", resource=TableResource(database=""fixtures"", table=""facetable""), actor=request.actor, ) Use await .ensure_permission(action, resource=None, actor=None) when you need to enforce a permission and raise a Forbidden error automatically. Plugins that define new operations should return Action objects from register_actions(datasette) and can supply additional allow/deny rules by returning PermissionSQL objects from the permission_resources_sql(datasette, actor, action) hook. Those rules are merged with configuration allow blocks and actor restrictions to determine the final result for each check.","[""Authentication and permissions""]",[] authentication:permissionsdebugview,authentication,permissionsdebugview,Permissions debug tools,"The debug tool at /-/permissions is available to any actor with the permissions-debug permission. By default this is just the authenticated root user but you can open it up to all users by starting Datasette like this: datasette -s permissions.permissions-debug true data.db The permission debug tools answer four different questions: Why was this decision allowed or denied? Use Permission check view . It shows every matching rule, identifies the winning specificity level, applies actor restrictions and evaluates any required actions. Which resources can the current actor access? Use Allowed resources view to view an access map for a selected action. Which raw rules did Datasette and its plugins contribute? Use Permission rules view to inspect the rules before they are resolved into decisions. Which checks has this Datasette instance performed recently? Use /-/permissions to view recent permission activity. These tools are designed to help administrators and plugin authors understand and confirm the effective permissions configuration. These debug endpoints are exempt from the JSON API stability promise - their JSON shapes may change in future releases.","[""Authentication and permissions""]",[] changelog:cookie-methods,changelog,cookie-methods,Cookie methods,"Plugins can now use the new response.set_cookie() method to set cookies. A new request.cookies method on the :ref:internals_request` can be used to read incoming cookies.","[""Changelog"", ""0.44 (2020-06-11)""]",[] changelog:foreign-key-expansions,changelog,foreign-key-expansions,Foreign key expansions,"When Datasette detects a foreign key reference it attempts to resolve a label for that reference (automatically or using the label_column metadata option) so it can display a link to the associated row. This expansion is now also available for JSON and CSV representations of the table, using the new _labels=on query string option. See Expanding foreign key references for more details.","[""Changelog"", ""0.23 (2018-06-18)""]",[] changelog:id1,changelog,id1,Changelog,,[],[] changelog:id103,changelog,id103,0.25.2 (2018-12-16),"datasette publish heroku now uses the python-3.6.7 runtime Added documentation on how to build the documentation Added documentation covering our release process Upgraded to pytest 4.0.2","[""Changelog""]",[] changelog:id166,changelog,id166,0.17 (2018-04-13),Release 0.17 to fix issues with PyPI,"[""Changelog""]",[] changelog:id220,changelog,id220,0.11 (2017-11-14),"Added datasette publish now --force option. This calls now with --force - useful as it means you get a fresh copy of datasette even if Now has already cached that docker layer. Enable --cors by default when running in a container.","[""Changelog""]",[] changelog:id223,changelog,id223,0.9 (2017-11-13),"Added --sql_time_limit_ms and --extra-options . The serve command now accepts --sql_time_limit_ms for customizing the SQL time limit. The publish and package commands now accept --extra-options which can be used to specify additional options to be passed to the datasite serve command when it executes inside the resulting Docker containers.","[""Changelog""]",[] changelog:id33,changelog,id33,0.60 (2022-01-13),,"[""Changelog""]",[] changelog:id56,changelog,id56,0.51.1 (2020-10-31),Improvements to the new Binary data documentation page.,"[""Changelog""]",[] changelog:id57,changelog,id57,0.51 (2020-10-31),"A new visual design, plugin hooks for adding navigation options, better handling of binary data, URL building utility methods and better support for running Datasette behind a proxy.","[""Changelog""]",[] changelog:id96,changelog,id96,0.29 (2019-07-07),"ASGI, new plugin hooks, facet by date and much, much more...","[""Changelog""]",[] changelog:id99,changelog,id99,0.27.1 (2019-05-09),"Tiny bugfix release: don't install tests/ in the wrong place. Thanks, Veit Heller.","[""Changelog""]",[] changelog:json-api-breaking-changes,changelog,json-api-breaking-changes,JSON API: breaking changes,"JSON error responses now use a single canonical format across every endpoint: {""ok"": false, ""error"": ""..."", ""errors"": [...], ""status"": 400} . The error key joins all error messages together, errors is the full list of messages and status always matches the HTTP status code. The legacy title key is no longer included in JSON errors (it remains available to the HTML error template), and endpoints that previously returned bare {""error"": ...} objects have been updated. See Error responses . Every JSON object success response now includes ""ok"": true , including introspection endpoints such as /-/versions and /-/settings . /-/plugins.json , /-/databases.json and /-/actions.json now return objects - {""ok"": true, ""plugins"": [...]} and equivalents - instead of top-level JSON arrays, so these responses can gain additional keys in the future without a breaking change. The datasette plugins CLI command still outputs a plain array. /-/databases now only lists databases the current actor is allowed to view. It previously listed every attached database, including their filesystem paths, to any actor with view-instance . Requests with an invalid or expired Authorization: Bearer token now receive a 401 status with the standard error body and a WWW-Authenticate: Bearer error=""invalid_token"" header, instead of being silently treated as unauthenticated. Bearer tokens that no registered token handler recognizes are still ignored, so authentication plugins with their own token formats keep working. Plugin token handlers can raise the new datasette.TokenInvalid exception to trigger the same behavior. Permission errors for JSON requests now return the standard JSON error format with a 403 status. The default forbidden handling previously rendered an HTML error page even for .json requests. POST to a write canned query now returns a 400 error when the SQL fails to execute, instead of a 200 status with ""ok"": false in the body. The error response includes the standard error keys plus a ""redirect"" key. The row update API with ""return"": true now responds with a ""rows"" list, matching insert and upsert, instead of a singular ""row"" object. Row delete write failures - such as a constraint violation raised by a trigger - now return 400 instead of 500 , matching the other write endpoints. //-/query.json with a missing or blank ?sql= parameter now returns a 400 error, as the CSV format already did, instead of a 200 with empty rows. Unknown ?_extra= names now return a 400 error for JSON and other data formats, instead of being silently ignored. HTML pages continue to ignore unknown names. Table JSON responses now include next_url alongside next by default - both are null on the final page. The now-redundant ?_extra=next_url parameter has been removed. The stored query list JSON no longer includes has_more - ""next"": null is the end-of-results signal across the whole API. This change also uncovered and fixed a bug where the query list next_url pointed at the HTML page and was a relative path; it is now an absolute URL that preserves the requested format. Stored query JSON objects no longer duplicate the list of parameter names as both params and parameters - only parameters remains. The query create and update APIs no longer accept params as an input alias either; params is still the documented key for queries defined in configuration . Page size parameters are now consistent across the API: the stored query lists accept ?_size=max and return a 400 error for values over the maximum instead of silently clamping them, and the /-/allowed and /-/rules permission debug endpoints renamed their page and page_size parameters to _page and _size , matching the underscore grammar used by every other Datasette system parameter. /-/threads now requires the permissions-debug permission, since it exposes runtime internals such as file paths. It previously only required view-instance . Trusted stored queries - those defined in configuration - can no longer be deleted through the JSON API or web interface, matching the existing restriction on editing them. The //-/schema endpoints now check the view-database permission before checking whether the database exists, so unauthorized actors can no longer probe for the existence of databases. SQL time limit errors in JSON responses are now a plain text message. The error string previously embedded an HTML fragment. The undocumented homepage JSON at /.json now returns databases as a list of objects rather than an object keyed by database name, matching every other collection in the API. The legacy .jsono format extension, long since superseded by ?_shape= , has been removed.","[""Changelog"", ""1.0a36 (2026-07-07)""]",[] changelog:json-api-other-improvements,changelog,json-api-other-improvements,JSON API: other improvements,"The write API endpoints now parse the request body as JSON regardless of the Content-Type header, so curl -d invocations work without remembering to set it. Invalid JSON is a 400 error. Cross-site request forgery remains prevented by Datasette's Origin and Sec-Fetch-Site checks. This also fixes a 500 error from the insert API when the Content-Type header was missing entirely. New Response.error(messages, status=400) helper for plugins that need to return a JSON error in Datasette's standard format. See Response class . New count_truncated extra for table JSON, included automatically whenever count is requested. true means the count reached Datasette's counting limit and the real number of rows may be higher. See Expanding JSON responses . JSON endpoints that are not part of the documented stable API now declare themselves with an ""unstable"" key in their responses. New documentation covering the grammar for boolean query string arguments , the reason upsert returns 200 where insert returns 201 , and advice for plugin authors on naming secret configuration keys so that /-/config redacts them automatically.","[""Changelog"", ""1.0a36 (2026-07-07)""]",[] changelog:signed-values-and-secrets,changelog,signed-values-and-secrets,Signed values and secrets,"Both flash messages and user authentication needed a way to sign values and set signed cookies. Two new methods are now available for plugins to take advantage of this mechanism: .sign(value, namespace=""default"") and .unsign(value, namespace=""default"") . Datasette will generate a secret automatically when it starts up, but to avoid resetting the secret (and hence invalidating any cookies) every time the server restarts you should set your own secret. You can pass a secret to Datasette using the new --secret option or with a DATASETTE_SECRET environment variable. See Configuring the secret for more details. You can also set a secret when you deploy Datasette using datasette publish or datasette package - see Using secrets with datasette publish . Plugins can now sign values and verify their signatures using the datasette.sign() and datasette.unsign() methods.","[""Changelog"", ""0.44 (2020-06-11)""]",[] changelog:v0-29-medium-changes,changelog,v0-29-medium-changes,Easier custom templates for table rows,"If you want to customize the display of individual table rows, you can do so using a _table.html template include that looks something like this: {% for row in display_rows %}

{{ row[""title""] }}

{{ row[""description""] }}

Category: {{ row.display(""category_id"") }}

{% endfor %} This is a backwards incompatible change . If you previously had a custom template called _rows_and_columns.html you need to rename it to _table.html . See Custom templates for full details.","[""Changelog"", ""0.29 (2019-07-07)""]",[] changelog:v1-0-a20,changelog,v1-0-a20,1.0a20 (2025-11-03),This alpha introduces a major breaking change prior to the 1.0 release of Datasette concerning how Datasette's permission system works.,"[""Changelog""]",[] changelog:v1-0-a24,changelog,v1-0-a24,1.0a24 (2026-01-29),,"[""Changelog""]",[] changelog:v1-0-a25,changelog,v1-0-a25,1.0a25 (2026-02-25),,"[""Changelog""]",[] changelog:v1-0-a26,changelog,v1-0-a26,1.0a26 (2026-03-18),,"[""Changelog""]",[] changelog:v1-0-a27,changelog,v1-0-a27,1.0a27 (2026-04-15),,"[""Changelog""]",[] changelog:v1-0-a31,changelog,v1-0-a31,1.0a31 (2026-05-28),"Datasette now offers users with the necessary permissions the ability to both execute write queries against their database and to save stored queries (renamed from ""canned queries"") both privately and for use by other members of their Datasette instance. The ability to write is controlled by the new execute-write-sql permission, but the user also needs the relevant insert-row / update-row / delete-row / create-table /etc permissions for the query they are trying to execute.","[""Changelog""]",[] changelog:v1-0-a33,changelog,v1-0-a33,1.0a33 (2026-06-11),"Stored queries can now be edited and deleted through the web interface, and the JSON API ?_extra= mechanism has been extended to cover row and query pages in addition to tables. This release also fixes two security issues: an identifier-quoting bug involving table and column names that contain ] , and an open redirect.","[""Changelog""]",[] changelog:v1-0-a9,changelog,v1-0-a9,1.0a9 (2024-02-16),This alpha release adds basic alter table support to the Datasette Write API and fixes a permissions bug relating to the /upsert API endpoint.,"[""Changelog""]",[] cli-reference:cli-datasette-get,cli-reference,cli-datasette-get,datasette --get,"The --get option to datasette serve (or just datasette ) specifies the path to a page within Datasette and causes Datasette to output the content from that path without starting the web server. This means that all of Datasette's functionality can be accessed directly from the command-line. For example: datasette --get '/-/versions.json' | jq . { ""python"": { ""version"": ""3.8.5"", ""full"": ""3.8.5 (default, Jul 21 2020, 10:48:26) \n[Clang 11.0.3 (clang-1103.0.32.62)]"" }, ""datasette"": { ""version"": ""0.46+15.g222a84a.dirty"" }, ""asgi"": ""3.0"", ""uvicorn"": ""0.11.8"", ""sqlite"": { ""version"": ""3.32.3"", ""fts_versions"": [ ""FTS5"", ""FTS4"", ""FTS3"" ], ""extensions"": { ""json1"": null }, ""compile_options"": [ ""COMPILER=clang-11.0.3"", ""ENABLE_COLUMN_METADATA"", ""ENABLE_FTS3"", ""ENABLE_FTS3_PARENTHESIS"", ""ENABLE_FTS4"", ""ENABLE_FTS5"", ""ENABLE_GEOPOLY"", ""ENABLE_JSON1"", ""ENABLE_PREUPDATE_HOOK"", ""ENABLE_RTREE"", ""ENABLE_SESSION"", ""MAX_VARIABLE_NUMBER=250000"", ""THREADSAFE=1"" ] } } You can use the --token TOKEN option to send an API token with the simulated request. Or you can make a request as a specific actor by passing a JSON representation of that actor to --actor : datasette --memory --actor '{""id"": ""root""}' --get '/-/actor.json' The exit code of datasette --get will be 0 if the request succeeds and 1 if the request produced an HTTP status code other than 200 - e.g. a 404 or 500 error. This lets you use datasette --get / to run tests against a Datasette application in a continuous integration environment such as GitHub Actions.","[""CLI reference"", ""datasette serve""]",[] cli-reference:cli-datasette-serve-env,cli-reference,cli-datasette-serve-env,Environment variables,"Some of the datasette serve options can be provided by environment variables: DATASETTE_SECRET : Equivalent to the --secret option. DATASETTE_SSL_KEYFILE : Equivalent to the --ssl-keyfile option. DATASETTE_SSL_CERTFILE : Equivalent to the --ssl-certfile option. DATASETTE_LOAD_EXTENSION : Equivalent to the --load-extension option.","[""CLI reference"", ""datasette serve""]",[] cli-reference:cli-help-create-token-help,cli-reference,cli-help-create-token-help,datasette create-token,"Create a signed API token, see datasette create-token . [[[cog help([""create-token"", ""--help""]) ]]] Usage: datasette create-token [OPTIONS] ID Create a signed API token for the specified actor ID Example: datasette create-token root --secret mysecret To allow only ""view-database-download"" for all databases: datasette create-token root --secret mysecret \ --all view-database-download To allow ""create-table"" against a specific database: datasette create-token root --secret mysecret \ --database mydb create-table To allow ""insert-row"" against a specific table: datasette create-token root --secret myscret \ --resource mydb mytable insert-row Restricted actions can be specified multiple times using multiple --all, --database, and --resource options. Add --debug to see a decoded version of the token. Options: --secret TEXT Secret used for signing the API tokens [required] -e, --expires-after INTEGER Token should expire after this many seconds -a, --all ACTION Restrict token to this action -d, --database DB ACTION Restrict token to this action on this database -r, --resource DB RESOURCE ACTION Restrict token to this action on this database resource (a table, SQL view or named query) --debug Show decoded token --plugins-dir DIRECTORY Path to directory containing custom plugins --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-help,cli-reference,cli-help-help,datasette --help,"Running datasette --help shows a list of all of the available commands. [[[cog help([""--help""]) ]]] Usage: datasette [OPTIONS] COMMAND [ARGS]... Datasette is an open source multi-tool for exploring and publishing data About Datasette: https://datasette.io/ Full documentation: https://docs.datasette.io/ Options: --version Show the version and exit. --help Show this message and exit. Commands: serve* Serve up specified SQLite database files with a web UI create-token Create a signed API token for the specified actor ID inspect Generate JSON summary of provided database files install Install plugins and packages from PyPI into the same... package Package SQLite files into a Datasette Docker container plugins List currently installed plugins publish Publish specified SQLite database files to the internet... uninstall Uninstall plugins and Python packages from the Datasette... [[[end]]] Additional commands added by plugins that use the register_commands(cli) hook will be listed here as well.","[""CLI reference""]",[] cli-reference:cli-help-inspect-help,cli-reference,cli-help-inspect-help,datasette inspect,"Outputs JSON representing introspected data about one or more SQLite database files. If you are opening an immutable database, you can pass this file to the --inspect-data option to improve Datasette's performance by allowing it to skip running row counts against the database when it first starts running: datasette inspect mydatabase.db > inspect-data.json datasette serve -i mydatabase.db --inspect-file inspect-data.json This performance optimization is used automatically by some of the datasette publish commands. You are unlikely to need to apply this optimization manually. [[[cog help([""inspect"", ""--help""]) ]]] Usage: datasette inspect [OPTIONS] [FILES]... Generate JSON summary of provided database files This can then be passed to ""datasette --inspect-file"" to speed up count operations against immutable database files. Options: --inspect-file TEXT --load-extension PATH:ENTRYPOINT? Path to a SQLite extension to load, and optional entrypoint --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-package-help,cli-reference,cli-help-package-help,datasette package,"Package SQLite files into a Datasette Docker container, see datasette package . [[[cog help([""package"", ""--help""]) ]]] Usage: datasette package [OPTIONS] FILES... Package SQLite files into a Datasette Docker container Options: -t, --tag TEXT Name for the resulting Docker container, can optionally use name:tag format -m, --metadata FILENAME Path to JSON/YAML file containing metadata to publish --extra-options TEXT Extra options to pass to datasette serve --branch TEXT Install datasette from a GitHub branch e.g. main --template-dir DIRECTORY Path to directory containing custom templates --plugins-dir DIRECTORY Path to directory containing custom plugins --static MOUNT:DIRECTORY Serve static files from this directory at /MOUNT/... --install TEXT Additional packages (e.g. plugins) to install --spatialite Enable SpatialLite extension --version-note TEXT Additional note to show on /-/versions --secret TEXT Secret used for signing secure values, such as signed cookies -p, --port INTEGER RANGE Port to run the server on, defaults to 8001 [1<=x<=65535] --title TEXT Title for metadata --license TEXT License label for metadata --license_url TEXT License URL for metadata --source TEXT Source label for metadata --source_url TEXT Source URL for metadata --about TEXT About label for metadata --about_url TEXT About URL for metadata --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-plugins-help,cli-reference,cli-help-plugins-help,datasette plugins,"Output JSON showing all currently installed plugins, their versions, whether they include static files or templates and which Plugin hooks they use. [[[cog help([""plugins"", ""--help""]) ]]] Usage: datasette plugins [OPTIONS] List currently installed plugins Options: --all Include built-in default plugins --requirements Output requirements.txt of installed plugins --plugins-dir DIRECTORY Path to directory containing custom plugins --help Show this message and exit. [[[end]]] Example output: [ { ""name"": ""datasette-geojson"", ""static"": false, ""templates"": false, ""version"": ""0.3.1"", ""hooks"": [ ""register_output_renderer"" ] }, { ""name"": ""datasette-geojson-map"", ""static"": true, ""templates"": false, ""version"": ""0.4.0"", ""hooks"": [ ""extra_body_script"", ""extra_css_urls"", ""extra_js_urls"" ] }, { ""name"": ""datasette-leaflet"", ""static"": true, ""templates"": false, ""version"": ""0.2.2"", ""hooks"": [ ""extra_body_script"", ""extra_template_vars"" ] } ]","[""CLI reference""]",[] cli-reference:cli-help-publish-cloudrun-help,cli-reference,cli-help-publish-cloudrun-help,datasette publish cloudrun,"See Publishing to Google Cloud Run . [[[cog help([""publish"", ""cloudrun"", ""--help""]) ]]] Usage: datasette publish cloudrun [OPTIONS] [FILES]... Publish databases to Datasette running on Cloud Run Options: -m, --metadata FILENAME Path to JSON/YAML file containing metadata to publish --extra-options TEXT Extra options to pass to datasette serve --branch TEXT Install datasette from a GitHub branch e.g. main --template-dir DIRECTORY Path to directory containing custom templates --plugins-dir DIRECTORY Path to directory containing custom plugins --static MOUNT:DIRECTORY Serve static files from this directory at /MOUNT/... --install TEXT Additional packages (e.g. plugins) to install --plugin-secret ... Secrets to pass to plugins, e.g. --plugin- secret datasette-auth-github client_id xxx --version-note TEXT Additional note to show on /-/versions --secret TEXT Secret used for signing secure values, such as signed cookies --title TEXT Title for metadata --license TEXT License label for metadata --license_url TEXT License URL for metadata --source TEXT Source label for metadata --source_url TEXT Source URL for metadata --about TEXT About label for metadata --about_url TEXT About URL for metadata -n, --name TEXT Application name to use when building --service TEXT Cloud Run service to deploy (or over-write) --spatialite Enable SpatialLite extension --show-files Output the generated Dockerfile and metadata.json --memory TEXT Memory to allocate in Cloud Run, e.g. 1Gi --cpu [1|2|4] Number of vCPUs to allocate in Cloud Run --timeout INTEGER Build timeout in seconds --apt-get-install TEXT Additional packages to apt-get install --max-instances INTEGER Maximum Cloud Run instances (use 0 to remove the limit) [default: 1] --min-instances INTEGER Minimum Cloud Run instances --artifact-repository TEXT Artifact Registry repository to store the image [default: datasette] --artifact-region TEXT Artifact Registry location (region or multi- region) [default: us] --artifact-project TEXT Project ID for Artifact Registry (defaults to the active project) --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-publish-help,cli-reference,cli-help-publish-help,datasette publish,"Shows a list of available deployment targets for publishing data with Datasette. Additional deployment targets can be added by plugins that use the publish_subcommand(publish) hook. [[[cog help([""publish"", ""--help""]) ]]] Usage: datasette publish [OPTIONS] COMMAND [ARGS]... Publish specified SQLite database files to the internet along with a Datasette-powered interface and API Options: --help Show this message and exit. Commands: cloudrun Publish databases to Datasette running on Cloud Run heroku Publish databases to Datasette running on Heroku [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-publish-heroku-help,cli-reference,cli-help-publish-heroku-help,datasette publish heroku,"See Publishing to Heroku . [[[cog help([""publish"", ""heroku"", ""--help""]) ]]] Usage: datasette publish heroku [OPTIONS] [FILES]... Publish databases to Datasette running on Heroku Options: -m, --metadata FILENAME Path to JSON/YAML file containing metadata to publish --extra-options TEXT Extra options to pass to datasette serve --branch TEXT Install datasette from a GitHub branch e.g. main --template-dir DIRECTORY Path to directory containing custom templates --plugins-dir DIRECTORY Path to directory containing custom plugins --static MOUNT:DIRECTORY Serve static files from this directory at /MOUNT/... --install TEXT Additional packages (e.g. plugins) to install --plugin-secret ... Secrets to pass to plugins, e.g. --plugin- secret datasette-auth-github client_id xxx --version-note TEXT Additional note to show on /-/versions --secret TEXT Secret used for signing secure values, such as signed cookies --title TEXT Title for metadata --license TEXT License label for metadata --license_url TEXT License URL for metadata --source TEXT Source label for metadata --source_url TEXT Source URL for metadata --about TEXT About label for metadata --about_url TEXT About URL for metadata -n, --name TEXT Application name to use when deploying --tar TEXT --tar option to pass to Heroku, e.g. --tar=/usr/local/bin/gtar --generate-dir DIRECTORY Output generated application files and stop without deploying --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-serve-help,cli-reference,cli-help-serve-help,datasette serve,"This command starts the Datasette web application running on your machine: datasette serve mydatabase.db Or since this is the default command you can run this instead: datasette mydatabase.db Once started you can access it at http://localhost:8001 [[[cog help([""serve"", ""--help""]) ]]] Usage: datasette serve [OPTIONS] [FILES]... Serve up specified SQLite database files with a web UI Options: -i, --immutable PATH Database files to open in immutable mode -h, --host TEXT Host for server. Defaults to 127.0.0.1 which means only connections from the local machine will be allowed. Use 0.0.0.0 to listen to all IPs and allow access from other machines. -p, --port INTEGER RANGE Port for server, defaults to 8001. Use -p 0 to automatically assign an available port. [0<=x<=65535] --uds TEXT Bind to a Unix domain socket --reload Automatically reload if code or metadata change detected - useful for development --cors Enable CORS by serving Access-Control-Allow- Origin: * --load-extension PATH:ENTRYPOINT? Path to a SQLite extension to load, and optional entrypoint --inspect-file TEXT Path to JSON file created using ""datasette inspect"" -m, --metadata FILENAME Path to JSON/YAML file containing license/source metadata --template-dir DIRECTORY Path to directory containing custom templates --plugins-dir DIRECTORY Path to directory containing custom plugins --static MOUNT:DIRECTORY Serve static files from this directory at /MOUNT/... --memory Make /_memory database available -c, --config FILENAME Path to JSON/YAML Datasette configuration file -s, --setting SETTING... nested.key, value setting to use in Datasette configuration --secret TEXT Secret used for signing secure values, such as signed cookies --root Output URL that sets a cookie authenticating the root user --default-deny Deny all permissions by default --get TEXT Run an HTTP GET request against this path, print results and exit --headers Include HTTP headers in --get output --token TEXT API token to send with --get requests --actor TEXT Actor to use for --get requests (JSON string) --version-note TEXT Additional note to show on /-/versions --help-settings Show available settings --pdb Launch debugger on any errors -o, --open Open Datasette in your web browser --create Create database files if they do not exist --crossdb Enable cross-database joins using the /_memory database --nolock Ignore locking, open locked files in read-only mode --ssl-keyfile TEXT SSL key file --ssl-certfile TEXT SSL certificate file --internal PATH Path to a persistent Datasette internal SQLite database --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:cli-help-serve-help-settings,cli-reference,cli-help-serve-help-settings,datasette serve --help-settings,"This command outputs all of the available Datasette settings . These can be passed to datasette serve using datasette serve --setting name value . [[[cog help([""--help-settings""]) ]]] Settings: default_page_size Default page size for the table view (default=100) max_returned_rows Maximum rows that can be returned from a table or custom query (default=1000) max_insert_rows Maximum rows that can be inserted at a time using the bulk insert API (default=100) max_post_body_bytes Maximum size in bytes for a POST body read into memory, e.g. JSON API requests - set 0 to disable this limit (default=2097152) num_sql_threads Number of threads in the thread pool for executing SQLite queries (default=3) sql_time_limit_ms Time limit for a SQL query in milliseconds (default=1000) default_facet_size Number of values to return for requested facets (default=30) facet_time_limit_ms Time limit for calculating a requested facet (default=200) facet_suggest_time_limit_ms Time limit for calculating a suggested facet (default=50) allow_facet Allow users to specify columns to facet using ?_facet= parameter (default=True) allow_download Allow users to download the original SQLite database files (default=True) allow_signed_tokens Allow users to create and use signed API tokens (default=True) default_allow_sql Allow anyone to run arbitrary SQL queries (default=True) max_signed_tokens_ttl Maximum allowed expiry time for signed API tokens (default=0) suggest_facets Calculate and display suggested facets (default=True) default_cache_ttl Default HTTP cache TTL (used in Cache-Control: max-age= header) (default=5) cache_size_kb SQLite cache size in KB (0 == use SQLite default) (default=0) allow_csv_stream Allow .csv?_stream=1 to download all rows (ignoring max_returned_rows) (default=True) max_csv_mb Maximum size allowed for CSV export in MB - set 0 to disable this limit (default=100) truncate_cells_html Truncate cells longer than this in HTML table view - set 0 to disable (default=2048) force_https_urls Force URLs in API output to always use https:// protocol (default=False) template_debug Allow display of template debug information with ?_context=1 (default=False) trace_debug Allow display of SQL trace debug information with ?_trace=1 (default=False) base_url Datasette URLs should use this base path (default=/) [[[end]]]","[""CLI reference"", ""datasette serve""]",[] cli-reference:cli-help-uninstall-help,cli-reference,cli-help-uninstall-help,datasette uninstall,"Uninstall one or more plugins. [[[cog help([""uninstall"", ""--help""]) ]]] Usage: datasette uninstall [OPTIONS] PACKAGES... Uninstall plugins and Python packages from the Datasette environment Options: -y, --yes Don't ask for confirmation --help Show this message and exit. [[[end]]]","[""CLI reference""]",[] cli-reference:id1,cli-reference,id1,CLI reference,"The datasette CLI tool provides a number of commands. Running datasette without specifying a command runs the default command, datasette serve . See datasette serve for the full list of options for that command. [[[cog from datasette import cli from click.testing import CliRunner import textwrap def help(args): title = ""datasette "" + "" "".join(args) cog.out(""\n::\n\n"") result = CliRunner().invoke(cli.cli, args) output = result.output.replace(""Usage: cli "", ""Usage: datasette "") cog.out(textwrap.indent(output, ' ')) cog.out(""\n\n"") ]]] [[[end]]]",[],[] configuration:configuration-reference,configuration,configuration-reference,,"The following example shows some of the valid configuration options that can exist inside datasette.yaml . [[[cog from metadata_doc import config_example import textwrap config_example(cog, textwrap.dedent( """""" # Datasette settings block settings: default_page_size: 50 sql_time_limit_ms: 3500 max_returned_rows: 2000 # top-level plugin configuration plugins: datasette-my-plugin: key: valueA # Database and table-level configuration databases: your_db_name: # plugin configuration for the your_db_name database plugins: datasette-my-plugin: key: valueA tables: your_table_name: allow: # Only the root user can access this table id: root # plugin configuration for the your_table_name table # inside your_db_name database plugins: datasette-my-plugin: key: valueB """""") ) ]]] [[[end]]]","[""Configuration""]",[] configuration:configuration-reference-permissions,configuration,configuration-reference-permissions,Permissions configuration,"Datasette's authentication and permissions system can also be configured using datasette.yaml . Here is a simple example: [[[cog from metadata_doc import config_example import textwrap config_example(cog, textwrap.dedent( """""" # Instance is only available to users 'sharon' and 'percy': allow: id: - sharon - percy # Only 'percy' is allowed access to the accounting database: databases: accounting: allow: id: percy """""").strip() ) ]]] [[[end]]] Access permissions in datasette.yaml has the full details.","[""Configuration"", null]",[] configuration:configuration-reference-plugins,configuration,configuration-reference-plugins,Plugin configuration,"Datasette plugins often require configuration. This plugin configuration should be placed in plugins keys inside datasette.yaml . Most plugins are configured at the top-level of the file, using the plugins key: [[[cog from metadata_doc import config_example import textwrap config_example(cog, textwrap.dedent( """""" # inside datasette.yaml plugins: datasette-my-plugin: key: my_value """""").strip() ) ]]] [[[end]]] Some plugins can be configured at the database or table level. These should use a plugins key nested under the appropriate place within the databases object: [[[cog from metadata_doc import config_example import textwrap config_example(cog, textwrap.dedent( """""" # inside datasette.yaml databases: my_database: # plugin configuration for the my_database database plugins: datasette-my-plugin: key: my_value my_other_database: tables: my_table: # plugin configuration for the my_table table inside the my_other_database database plugins: datasette-my-plugin: key: my_value """""").strip() ) ]]] [[[end]]]","[""Configuration"", null]",[] configuration:configuration-reference-queries,configuration,configuration-reference-queries,Queries configuration,"Queries are named SQL queries that appear in the Datasette interface. They can be configured in datasette.yaml using the queries key at the database level: [[[cog from metadata_doc import config_example, config_example config_example(cog, { ""databases"": { ""sf-trees"": { ""queries"": { ""just_species"": { ""sql"": ""select qSpecies from Street_Tree_List"" } } } } }) ]]] [[[end]]] See the queries documentation for more, including how to configure writable queries .","[""Configuration"", null]",[] configuration:configuration-reference-settings,configuration,configuration-reference-settings,Settings,"Settings can be configured in datasette.yaml with the settings key: [[[cog from metadata_doc import config_example import textwrap config_example(cog, textwrap.dedent( """""" # inside datasette.yaml settings: default_allow_sql: off default_page_size: 50 """""").strip() ) ]]] [[[end]]] The full list of settings is available in the settings documentation . Settings can also be passed to Datasette using one or more --setting name value command line options.`","[""Configuration"", null]",[] configuration:configuration-reference-table,configuration,configuration-reference-table,Table configuration,Datasette supports a number of table-level configuration options inside datasette.yaml . These are placed under databases.database_name.tables.table_name .,"[""Configuration"", null]",[] configuration:id1,configuration,id1,Configuration,"Datasette offers several ways to configure your Datasette instances: server settings, plugin configuration, authentication, and more. Most configuration can be handled using a datasette.yaml configuration file, passed to datasette using the -c/--config flag: datasette mydatabase.db --config datasette.yaml This file can also use JSON, as datasette.json . YAML is recommended over JSON due to its support for comments and multi-line strings.",[],[] configuration:table-configuration-column-types,configuration,table-configuration-column-types,,"You can assign semantic column types to columns, which affect how values are rendered, validated, transformed, and edited. Built-in column types include url , email , json , and textarea . Plugins can register additional column types using the register_column_types plugin hook. Column types can optionally declare which SQLite column types they apply to using sqlite_types . Datasette will reject incompatible assignments. The built-in url , email , json , and textarea column types are all restricted to TEXT columns. The simplest form maps column names to type name strings: [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: column_types: website: url contact: email extra_data: json notes: textarea """""").strip() ) ]]] [[[end]]] For column types that accept additional configuration, use an object with type and config keys: [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: column_types: website: type: url config: prefix: ""https://"" """""").strip() ) ]]] [[[end]]]","[""Configuration"", null, ""Table configuration""]",[] configuration:table-configuration-facets,configuration,table-configuration-facets,,"You can turn on facets by default for specific tables. facet_size controls how many unique values are shown for each facet on that table (the default is controlled by the default_facet_size setting). See Facets in configuration for full details. [[[cog config_example(cog, textwrap.dedent( """""" databases: sf-trees: tables: Street_Tree_List: facets: - qLegalStatus facet_size: 10 """""").strip() ) ]]] [[[end]]] You can also specify array or date facets using JSON objects with a single key of array or date : facets: - array: tags - date: created","[""Configuration"", null, ""Table configuration""]",[] configuration:table-configuration-hidden,configuration,table-configuration-hidden,,"You can hide tables from the database listing view (in the same way that FTS and SpatiaLite tables are automatically hidden) using ""hidden"": true : [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: hidden: true """""").strip() ) ]]] [[[end]]]","[""Configuration"", null, ""Table configuration""]",[] configuration:table-configuration-label-column,configuration,table-configuration-label-column,,"Datasette's HTML interface attempts to display foreign key references as labelled hyperlinks. By default, it automatically detects a label column using the following rules (in order): If there is exactly one unique text column, use that. If there is a column called name or title (case-insensitive), use that. If the table has only two columns - a primary key and one other - use the non-primary-key column. You can override this automatic detection by specifying which column should be used for the link label with the label_column property: [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: label_column: title """""").strip() ) ]]] [[[end]]]","[""Configuration"", null, ""Table configuration""]",[] configuration:table-configuration-size,configuration,table-configuration-size,,"Datasette defaults to displaying 100 rows per page, for both tables and views. You can change this on a per-table or per-view basis using the size key: [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: size: 10 """""").strip() ) ]]] [[[end]]] This size can still be over-ridden by passing e.g. ?_size=50 in the query string.","[""Configuration"", null, ""Table configuration""]",[] configuration:table-configuration-sort,configuration,table-configuration-sort,,"By default Datasette tables are sorted by primary key. You can set a default sort order for a specific table using the sort or sort_desc properties: [[[cog from metadata_doc import config_example import textwrap config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: sort: created """""").strip() ) ]]] [[[end]]] Or use sort_desc to sort in descending order: [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: sort_desc: created """""").strip() ) ]]] [[[end]]]","[""Configuration"", null, ""Table configuration""]",[] configuration:table-configuration-sortable-columns,configuration,table-configuration-sortable-columns,,"Datasette allows any column to be used for sorting by default. If you need to control which columns are available for sorting you can do so using sortable_columns : [[[cog config_example(cog, textwrap.dedent( """""" databases: mydatabase: tables: example_table: sortable_columns: - height - weight """""").strip() ) ]]] [[[end]]] This will restrict sorting of example_table to just the height and weight columns. You can also disable sorting entirely by setting ""sortable_columns"": [] You can use sortable_columns to enable specific sort orders for a view called name_of_view in the database my_database like so: [[[cog config_example(cog, textwrap.dedent( """""" databases: my_database: tables: name_of_view: sortable_columns: - clicks - impressions """""").strip() ) ]]] [[[end]]]","[""Configuration"", null, ""Table configuration""]",[] contributing:contributing-formatting-black,contributing,contributing-formatting-black,Running Black,"Black is installed as part of the development dependency group. To test that your code complies with Black, run the following in your root datasette repository checkout: uv run black . --check All done! ✨ 🍰 ✨ 95 files would be left unchanged. If any of your code does not conform to Black you can run this to automatically fix those problems: uv run black . reformatted ../datasette/app.py All done! ✨ 🍰 ✨ 1 file reformatted, 94 files left unchanged.","[""Contributing"", ""Code formatting""]",[] contributing:contributing-template-contexts,contributing,contributing-template-contexts,Documented template contexts,"Datasette's documented template contexts are part of the public API for custom templates. They are defined as dataclasses next to the view code that renders them, for example DatabaseContext and QueryContext in datasette/views/database.py . Every documented context class inherits from datasette.views.Context . Fields that are added directly by view code should be declared as dataclass fields with help metadata, which is used to generate Template context . Fields resolved through the page extras system should use from_extra() so their documentation comes from the matching Extra class. Use documented_template on each context class to record the canonical template named in the generated documentation. This should be a string such as ""database.html"" . Runtime template selection still happens in the view code, since most pages consider more specific template names before falling back to the canonical one. When a context field contains repeated structured data, prefer a small nested dataclass over an anonymous dictionary. For example, a field containing table summaries should be annotated as list[DatabaseTable] where DatabaseTable is a dataclass describing the keys and value types. This keeps the Python contract and generated documentation clear. JSON responses and ?_context=1 debug output will convert nested dataclasses back to JSON objects at the response boundary.","[""Contributing"", ""Editing and building the documentation""]",[] contributing:contributing-using-fixtures,contributing,contributing-using-fixtures,Using fixtures,"To run Datasette itself, type datasette . You're going to need at least one SQLite database. A quick way to get started is to use the fixtures database that Datasette uses for its own tests. You can create a copy of that database by running this command: uv run python tests/fixtures.py fixtures.db Now you can run Datasette against the new fixtures database like so: uv run datasette fixtures.db This will start a server at http://127.0.0.1:8001/ . Any changes you make in the datasette/templates or datasette/static folder will be picked up immediately (though you may need to do a force-refresh in your browser to see changes to CSS or JavaScript). If you want to change Datasette's Python code you can use the --reload option to cause Datasette to automatically reload any time the underlying code changes: uv run datasette --reload fixtures.db This also enables development mode for static asset cache busting, described in Linking to static assets . You can also use the fixtures.py script to recreate the testing version of metadata.json used by the unit tests. To do that: uv run python tests/fixtures.py fixtures.db fixtures-metadata.json Or to output the plugins used by the tests, run this: uv run python tests/fixtures.py fixtures.db fixtures-metadata.json fixtures-plugins Test tables written to fixtures.db - metadata written to fixtures-metadata.json Wrote plugin: fixtures-plugins/register_output_renderer.py Wrote plugin: fixtures-plugins/view_name.py Wrote plugin: fixtures-plugins/my_plugin.py Wrote plugin: fixtures-plugins/messages_output_renderer.py Wrote plugin: fixtures-plugins/my_plugin_2.py Then run Datasette like this: uv run datasette fixtures.db -m fixtures-metadata.json --plugins-dir=fixtures-plugins/","[""Contributing""]",[] contributing:general-guidelines,contributing,general-guidelines,General guidelines,"main should always be releasable . Incomplete features should live in branches. This ensures that any small bug fixes can be quickly released. The ideal commit should bundle together the implementation, unit tests and associated documentation updates. The commit message should link to an associated issue. New plugin hooks should only be shipped if accompanied by a separate release of a non-demo plugin that uses them. New user-facing views and documentation should be added or updated alongside their implementation. The /docs folder includes pages for plugin hooks and built-in views—please ensure any new hooks or views are reflected there so the documentation tests continue to pass.","[""Contributing""]",[] contributing:id1,contributing,id1,Contributing,"Datasette is an open source project. We welcome contributions! This document describes how to contribute to Datasette core. You can also contribute to the wider Datasette ecosystem by creating new Plugins .",[],[] csv_export:csv-export-url-parameters,csv_export,csv-export-url-parameters,URL parameters,"The following options can be used to customize the CSVs returned by Datasette. ?_header=off This removes the first row of the CSV file specifying the headings - only the row data will be returned. ?_stream=on Stream all matching records, not just the first page of results. See below. ?_dl=on Causes Datasette to return a content-disposition: attachment; filename=""filename.csv"" header.","[""CSV export""]",[] csv_export:streaming-all-records,csv_export,streaming-all-records,Streaming all records,"The stream all rows option is designed to be as efficient as possible - under the hood it takes advantage of Python 3 asyncio capabilities and Datasette's efficient pagination to stream back the full CSV file. Since databases can get pretty large, by default this option is capped at 100MB - if a table returns more than 100MB of data the last line of the CSV will be a truncation error message. You can increase or remove this limit using the max_csv_mb config setting. You can also disable the CSV export feature entirely using allow_csv_stream .","[""CSV export""]",[] custom_templates:css-classes-on-the-body,custom_templates,css-classes-on-the-body,CSS classes on the ,"Every default template includes CSS classes in the body designed to support custom styling. The index template (the top level page at / ) gets this: The database template ( /dbname ) gets this: The custom SQL template ( /dbname?sql=... ) gets this: A stored query template ( /dbname/queryname ) gets this: The table template ( /dbname/tablename ) gets: The row template ( /dbname/tablename/rowid ) gets: The db-x and table-x classes use the database or table names themselves if they are valid CSS identifiers. If they aren't, we strip any invalid characters out and append a 6 character md5 digest of the original name, in order to ensure that multiple tables which resolve to the same stripped character version still have different CSS classes. Some examples: ""simple"" => ""simple"" ""MixedCase"" => ""MixedCase"" ""-no-leading-hyphens"" => ""no-leading-hyphens-65bea6"" ""_no-leading-underscores"" => ""no-leading-underscores-b921bc"" ""no spaces"" => ""no-spaces-7088d7"" ""-"" => ""336d5e"" ""no $ characters"" => ""no--characters-59e024"" and elements also get custom CSS classes reflecting the database column they are representing, for example:
id name
1 SMITH
","[""Custom pages and templates""]",[] custom_templates:custom-pages-404,custom_templates,custom-pages-404,Returning 404s,"To indicate that content could not be found and display the default 404 page you can use the raise_404(message) function: {% if not rows %} {{ raise_404(""Content not found"") }} {% endif %} If you call raise_404() the other content in your template will be ignored.","[""Custom pages and templates""]",[] custom_templates:custom-pages-headers,custom_templates,custom-pages-headers,Custom headers and status codes,"Custom pages default to being served with a content-type of text/html; charset=utf-8 and a 200 status code. You can change these by calling a custom function from within your template. For example, to serve a custom page with a 418 I'm a teapot HTTP status code, create a file in pages/teapot.html containing the following: {{ custom_status(418) }} Teapot I'm a teapot To serve a custom HTTP header, add a custom_header(name, value) function call. For example: {{ custom_status(418) }} {{ custom_header(""x-teapot"", ""I am"") }} Teapot I'm a teapot You can verify this is working using curl like this: curl -I 'http://127.0.0.1:8001/teapot' HTTP/1.1 418 date: Sun, 26 Apr 2020 18:38:30 GMT server: uvicorn x-teapot: I am content-type: text/html; charset=utf-8","[""Custom pages and templates""]",[]