element, to help with advanced CSS customization. ( #1446 )
The render_cell() plugin hook can now return an awaitable function. This means the hook can execute SQL queries. ( #1425 )
register_routes(datasette) plugin hook now accepts an optional datasette argument. ( #1404 )
New hide_sql canned query option for defaulting to hiding the SQL query used by a canned query, see Additional canned query options . ( #1422 )
New --cpu option for datasette publish cloudrun . ( #1420 )
If Rich is installed in the same virtual environment as Datasette, it will be used to provide enhanced display of error tracebacks on the console. ( #1416 )
datasette.utils parse_metadata(content) function, used by the new datasette-remote-metadata plugin , is now a documented API. ( #1405 )
Fixed bug where ?_next=x&_sort=rowid could throw an error. ( #1470 )
Column cog menu no longer shows the option to facet by a column that is already selected by the default facets in metadata. ( #1469 )","[""Changelog""]","[{""href"": ""https://github.com/simonw/datasette/issues/942"", ""label"": ""#942""}, {""href"": ""https://github.com/simonw/datasette/issues/1449"", ""label"": ""#1449""}, {""href"": ""https://github.com/simonw/datasette/issues/1423"", ""label"": ""#1423""}, {""href"": ""https://github.com/encode/httpx/releases/tag/0.20.0"", ""label"": ""httpx 0.20""}, {""href"": ""https://github.com/simonw/datasette/issues/1488"", ""label"": ""#1488""}, {""href"": ""https://github.com/simonw/datasette/pull/1467"", ""label"": ""#1467""}, {""href"": ""https://github.com/simonw/datasette/issues/1421"", ""label"": ""#1421""}, {""href"": ""https://github.com/simonw/datasette/issues/1431"", ""label"": ""#1431""}, {""href"": ""https://github.com/simonw/datasette/issues/1443"", ""label"": ""#1443""}, {""href"": ""https://github.com/simonw/datasette/issues/1446"", ""label"": ""#1446""}, {""href"": ""https://github.com/simonw/datasette/issues/1425"", ""label"": ""#1425""}, {""href"": ""https://github.com/simonw/datasette/issues/1404"", ""label"": ""#1404""}, {""href"": ""https://github.com/simonw/datasette/issues/1422"", ""label"": ""#1422""}, {""href"": ""https://github.com/simonw/datasette/issues/1420"", ""label"": ""#1420""}, {""href"": ""https://github.com/willmcgugan/rich"", ""label"": ""Rich""}, {""href"": ""https://github.com/simonw/datasette/issues/1416"", ""label"": ""#1416""}, {""href"": ""https://datasette.io/plugins/datasette-remote-metadata"", ""label"": ""datasette-remote-metadata plugin""}, {""href"": ""https://github.com/simonw/datasette/issues/1405"", ""label"": ""#1405""}, {""href"": ""https://github.com/simonw/datasette/issues/1470"", ""label"": ""#1470""}, {""href"": ""https://github.com/simonw/datasette/issues/1469"", ""label"": ""#1469""}]"
changelog:id50,changelog,id50,0.49.1 (2020-09-15),Fixed a bug with writable canned queries that use magic parameters but accept no non-magic arguments. ( #967 ),"[""Changelog""]","[{""href"": ""https://github.com/simonw/datasette/issues/967"", ""label"": ""#967""}]"
changelog:id43,changelog,id43,0.52 (2020-11-28),"This release includes a number of changes relating to an internal rebranding effort: Datasette's configuration mechanism (things like datasette --config default_page_size:10 ) has been renamed to settings .
New --setting default_page_size 10 option as a replacement for --config default_page_size:10 (note the lack of a colon). The --config option is deprecated but will continue working until Datasette 1.0. ( #992 )
The /-/config introspection page is now /-/settings , and the previous page redirects to the new one. ( #1103 )
The config.json file in Configuration directory mode is now called settings.json . ( #1104 )
The undocumented datasette.config() internal method has been replaced by a documented .setting(key) method. ( #1107 )
Also in this release:
New plugin hook: database_actions(datasette, actor, database, request) , which adds menu items to a new cog menu shown at the top of the database page. ( #1077 )
datasette publish cloudrun has a new --apt-get-install option that can be used to install additional Ubuntu packages as part of the deployment. This is useful for deploying the new datasette-ripgrep plugin . ( #1110 )
Swept the documentation to remove words that minimize involved difficulty. ( #1089 )
And some bug fixes:
Foreign keys linking to rows with blank label columns now display as a hyphen, allowing those links to be clicked. ( #1086 )
Fixed bug where row pages could sometimes 500 if the underlying queries exceeded a time limit. ( #1088 )
Fixed a bug where the table action menu could appear partially obscured by the edge of the page. ( #1084 )","[""Changelog""]","[{""href"": ""https://github.com/simonw/datasette/issues/992"", ""label"": ""#992""}, {""href"": ""https://github.com/simonw/datasette/issues/1103"", ""label"": ""#1103""}, {""href"": ""https://github.com/simonw/datasette/issues/1104"", ""label"": ""#1104""}, {""href"": ""https://github.com/simonw/datasette/issues/1107"", ""label"": ""#1107""}, {""href"": ""https://github.com/simonw/datasette/issues/1077"", ""label"": ""#1077""}, {""href"": ""https://github.com/simonw/datasette-ripgrep"", ""label"": ""datasette-ripgrep plugin""}, {""href"": ""https://github.com/simonw/datasette/issues/1110"", ""label"": ""#1110""}, {""href"": ""https://github.com/simonw/datasette/issues/1089"", ""label"": ""#1089""}, {""href"": ""https://github.com/simonw/datasette/issues/1086"", ""label"": ""#1086""}, {""href"": ""https://github.com/simonw/datasette/issues/1088"", ""label"": ""#1088""}, {""href"": ""https://github.com/simonw/datasette/issues/1084"", ""label"": ""#1084""}]"
changelog:id46,changelog,id46,Smaller changes,"Wide tables shown within Datasette now scroll horizontally ( #998 ). This is achieved using a new
element which may impact the implementation of some plugins (for example this change to datasette-cluster-map ).
New debug-menu permission. ( #1068 )
Removed --debug option, which didn't do anything. ( #814 )
Link: HTTP header pagination. ( #1014 )
x button for clearing filters. ( #1016 )
Edit SQL button on canned queries, ( #1019 )
--load-extension=spatialite shortcut. ( #1028 )
scale-in animation for column action menu. ( #1039 )
Option to pass a list of templates to .render_template() is now documented. ( #1045 )
New datasette.urls.static_plugins() method. ( #1033 )
datasette -o option now opens the most relevant page. ( #976 )
datasette --cors option now enables access to /database.db downloads. ( #1057 )
Database file downloads now implement cascading permissions, so you can download a database if you have view-database-download permission even if you do not have permission to access the Datasette instance. ( #1058 )
New documentation on Designing URLs for your plugin . ( #1053 )","[""Changelog"", ""0.51 (2020-10-31)""]","[{""href"": ""https://github.com/simonw/datasette/issues/998"", ""label"": ""#998""}, {""href"": ""https://github.com/simonw/datasette-cluster-map/commit/fcb4abbe7df9071c5ab57defd39147de7145b34e"", ""label"": ""this change to datasette-cluster-map""}, {""href"": ""https://github.com/simonw/datasette/issues/1068"", ""label"": ""#1068""}, {""href"": ""https://github.com/simonw/datasette/issues/814"", ""label"": ""#814""}, {""href"": ""https://github.com/simonw/datasette/issues/1014"", ""label"": ""#1014""}, {""href"": ""https://github.com/simonw/datasette/issues/1016"", ""label"": ""#1016""}, {""href"": ""https://github.com/simonw/datasette/issues/1019"", ""label"": ""#1019""}, {""href"": ""https://github.com/simonw/datasette/issues/1028"", ""label"": ""#1028""}, {""href"": ""https://github.com/simonw/datasette/issues/1039"", ""label"": ""#1039""}, {""href"": ""https://github.com/simonw/datasette/issues/1045"", ""label"": ""#1045""}, {""href"": ""https://github.com/simonw/datasette/issues/1033"", ""label"": ""#1033""}, {""href"": ""https://github.com/simonw/datasette/issues/976"", ""label"": ""#976""}, {""href"": ""https://github.com/simonw/datasette/issues/1057"", ""label"": ""#1057""}, {""href"": ""https://github.com/simonw/datasette/issues/1058"", ""label"": ""#1058""}, {""href"": ""https://github.com/simonw/datasette/issues/1053"", ""label"": ""#1053""}]"
internals:internals-utils,internals,internals-utils,The datasette.utils module,"The datasette.utils module contains various utility functions used by Datasette. As a general rule you should consider anything in this module to be unstable - functions and classes here could change without warning or be removed entirely between Datasette releases, without being mentioned in the release notes.
The exception to this rule is anything that is documented here. If you find a need for an undocumented utility function in your own work, consider opening an issue requesting that the function you are using be upgraded to documented and supported status.","[""Internals for plugins""]","[{""href"": ""https://github.com/simonw/datasette/issues/new"", ""label"": ""opening an issue""}]"
changelog:the-road-to-datasette-1-0,changelog,the-road-to-datasette-1-0,The road to Datasette 1.0,"I've assembled a milestone for Datasette 1.0 . The focus of the 1.0 release will be the following:
Signify confidence in the quality/stability of Datasette
Give plugin authors confidence that their plugins will work for the whole 1.x release cycle
Provide the same confidence to developers building against Datasette JSON APIs
If you have thoughts about what you would like to see for Datasette 1.0 you can join the conversation on issue #519 .","[""Changelog"", ""0.44 (2020-06-11)""]","[{""href"": ""https://github.com/simonw/datasette/milestone/7"", ""label"": ""milestone for Datasette 1.0""}, {""href"": ""https://github.com/simonw/datasette/issues/519"", ""label"": ""the conversation on issue #519""}]"
changelog:v0-28-register-output-renderer,changelog,v0-28-register-output-renderer,register_output_renderer plugins,"Russ Garrett implemented a new Datasette plugin hook called register_output_renderer ( #441 ) which allows plugins to create additional output renderers in addition to Datasette's default .json and .csv .
Russ's in-development datasette-geo plugin includes an example of this hook being used to output .geojson automatically converted from SpatiaLite.","[""Changelog"", ""0.28 (2019-05-19)""]","[{""href"": ""https://github.com/simonw/datasette/pull/441"", ""label"": ""#441""}, {""href"": ""https://github.com/russss/datasette-geo"", ""label"": ""datasette-geo""}, {""href"": ""https://github.com/russss/datasette-geo/blob/d4cecc020848bbde91e9e17bf352f7c70bc3dccf/datasette_plugin_geo/geojson.py"", ""label"": ""an example""}]"
changelog:id77,changelog,id77,0.31 (2019-11-11),"This version adds compatibility with Python 3.8 and breaks compatibility with Python 3.5.
If you are still running Python 3.5 you should stick with 0.30.2 , which you can install like this:
pip install datasette==0.30.2
Format SQL button now works with read-only SQL queries - thanks, Tobias Kunze ( #602 )
New ?column__notin=x,y,z filter for table views ( #614 )
Table view now uses select col1, col2, col3 instead of select *
Database filenames can now contain spaces - thanks, Tobias Kunze ( #590 )
Removed obsolete ?_group_count=col feature ( #504 )
Improved user interface and documentation for datasette publish cloudrun ( #608 )
Tables with indexes now show the CREATE INDEX statements on the table page ( #618 )
Current version of uvicorn is now shown on /-/versions
Python 3.8 is now supported! ( #622 )
Python 3.5 is no longer supported.","[""Changelog""]","[{""href"": ""https://github.com/simonw/datasette/pull/602"", ""label"": ""#602""}, {""href"": ""https://github.com/simonw/datasette/issues/614"", ""label"": ""#614""}, {""href"": ""https://github.com/simonw/datasette/pull/590"", ""label"": ""#590""}, {""href"": ""https://github.com/simonw/datasette/issues/504"", ""label"": ""#504""}, {""href"": ""https://github.com/simonw/datasette/issues/608"", ""label"": ""#608""}, {""href"": ""https://github.com/simonw/datasette/issues/618"", ""label"": ""#618""}, {""href"": ""https://www.uvicorn.org/"", ""label"": ""uvicorn""}, {""href"": ""https://github.com/simonw/datasette/issues/622"", ""label"": ""#622""}]"
changelog:id76,changelog,id76,0.31.1 (2019-11-12),Deployments created using datasette publish now use python:3.8 base Docker image ( #629 ),"[""Changelog""]","[{""href"": ""https://github.com/simonw/datasette/pull/629"", ""label"": ""#629""}]"
contributing:contributing-bug-fix-branch,contributing,contributing-bug-fix-branch,Releasing bug fixes from a branch,"If it's necessary to publish a bug fix release without shipping new features that have landed on main a release branch can be used.
Create it from the relevant last tagged release like so:
git branch 0.52.x 0.52.4
git checkout 0.52.x
Next cherry-pick the commits containing the bug fixes:
git cherry-pick COMMIT
Write the release notes in the branch, and update the version number in version.py . Then push the branch:
git push -u origin 0.52.x
Once the tests have completed, publish the release from that branch target using the GitHub Draft a new release form.
Finally, cherry-pick the commit with the release notes and version number bump across to main :
git checkout main
git cherry-pick COMMIT
git push","[""Contributing""]","[{""href"": ""https://github.com/simonw/datasette/releases/new"", ""label"": ""Draft a new release""}]"
plugin_hooks:plugin-hook-publish-subcommand,plugin_hooks,plugin-hook-publish-subcommand,publish_subcommand(publish),"publish - Click publish command group
The Click command group for the datasette publish subcommand
This hook allows you to create new providers for the datasette publish
command. Datasette uses this hook internally to implement the default cloudrun
and heroku subcommands, so you can read
their source
to see examples of this hook in action.
Let's say you want to build a plugin that adds a datasette publish my_hosting_provider --api_key=xxx mydatabase.db publish command. Your implementation would start like this:
from datasette import hookimpl
from datasette.publish.common import (
add_common_publish_arguments_and_options,
)
import click
@hookimpl
def publish_subcommand(publish):
@publish.command()
@add_common_publish_arguments_and_options
@click.option(
""-k"",
""--api_key"",
help=""API key for talking to my hosting provider"",
)
def my_hosting_provider(
files,
metadata,
extra_options,
branch,
template_dir,
plugins_dir,
static,
install,
plugin_secret,
version_note,
secret,
title,
license,
license_url,
source,
source_url,
about,
about_url,
api_key,
): ...
Examples: datasette-publish-fly , datasette-publish-vercel","[""Plugin hooks""]","[{""href"": ""https://github.com/simonw/datasette/tree/main/datasette/publish"", ""label"": ""their source""}, {""href"": ""https://datasette.io/plugins/datasette-publish-fly"", ""label"": ""datasette-publish-fly""}, {""href"": ""https://datasette.io/plugins/datasette-publish-vercel"", ""label"": ""datasette-publish-vercel""}]"
changelog:id115,changelog,id115,0.22.1 (2018-05-23),"Bugfix release, plus we now use versioneer for our version numbers.
Faceting no longer breaks pagination, fixes #282
Add __version_info__ derived from __version__ [Robert Gieseke]
This might be tuple of more than two values (major and minor
version) if commits have been made after a release.
Add version number support with Versioneer. [Robert Gieseke]
Versioneer Licence:
Public Domain (CC0-1.0)
Closes #273
Refactor inspect logic [Russ Garrett]","[""Changelog""]","[{""href"": ""https://github.com/warner/python-versioneer"", ""label"": ""versioneer""}, {""href"": ""https://github.com/simonw/datasette/issues/282"", ""label"": ""#282""}, {""href"": ""https://github.com/simonw/datasette/issues/273"", ""label"": ""#273""}]"
getting_started:getting-started-glitch,getting_started,getting-started-glitch,Try Datasette without installing anything using Glitch,"Glitch is a free online tool for building web apps directly from your web browser. You can use Glitch to try out Datasette without needing to install any software on your own computer.
Here's a demo project on Glitch which you can use as the basis for your own experiments:
glitch.com/~datasette-csvs
Glitch allows you to ""remix"" any project to create your own copy and start editing it in your browser. You can remix the datasette-csvs project by clicking this button:
Find a CSV file and drag it onto the Glitch file explorer panel - datasette-csvs will automatically convert it to a SQLite database (using sqlite-utils ) and allow you to start exploring it using Datasette.
If your CSV file has a latitude and longitude column you can visualize it on a map by uncommenting the datasette-cluster-map line in the requirements.txt file using the Glitch file editor.
Need some data? Try this Public Art Data for the city of Seattle - hit ""Export"" and select ""CSV"" to download it as a CSV file.
For more on how this works, see Running Datasette on Glitch .","[""Getting started""]","[{""href"": ""https://glitch.com/"", ""label"": ""Glitch""}, {""href"": ""https://glitch.com/~datasette-csvs"", ""label"": ""glitch.com/~datasette-csvs""}, {""href"": ""https://glitch.com/edit/#!/remix/datasette-csvs"", ""label"": null}, {""href"": ""https://github.com/simonw/sqlite-utils"", ""label"": ""sqlite-utils""}, {""href"": ""https://data.seattle.gov/Community/Public-Art-Data/j7sn-tdzk"", ""label"": ""Public Art Data""}, {""href"": ""https://simonwillison.net/2019/Apr/23/datasette-glitch/"", ""label"": ""Running Datasette on Glitch""}]"
getting_started:getting-started-demo,getting_started,getting-started-demo,Play with a live demo,"The best way to experience Datasette for the first time is with a demo:
global-power-plants.datasettes.com provides a searchable database of power plants around the world, using data from the World Resources Institude rendered using the datasette-cluster-map plugin.
fivethirtyeight.datasettes.com shows Datasette running against over 400 datasets imported from the FiveThirtyEight GitHub repository .","[""Getting started""]","[{""href"": ""https://global-power-plants.datasettes.com/global-power-plants/global-power-plants"", ""label"": ""global-power-plants.datasettes.com""}, {""href"": ""https://www.wri.org/publication/global-power-plant-database"", ""label"": ""World Resources Institude""}, {""href"": ""https://github.com/simonw/datasette-cluster-map"", ""label"": ""datasette-cluster-map""}, {""href"": ""https://fivethirtyeight.datasettes.com/fivethirtyeight"", ""label"": ""fivethirtyeight.datasettes.com""}, {""href"": ""https://github.com/fivethirtyeight/data"", ""label"": ""FiveThirtyEight GitHub repository""}]"
deploying:apache-proxy-configuration,deploying,apache-proxy-configuration,Apache proxy configuration,"For Apache , you can use the ProxyPass directive. First make sure the following lines are uncommented:
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
Then add these directives to proxy traffic:
ProxyPass /my-datasette/ http://127.0.0.1:8009/my-datasette/
ProxyPreserveHost On
A live demo of Datasette running behind Apache using this proxy setup can be seen at datasette-apache-proxy-demo.datasette.io/prefix/ . The code for that demo can be found in the demos/apache-proxy directory.
Using --uds you can use Unix domain sockets similar to the nginx example:
ProxyPass /my-datasette/ unix:/tmp/datasette.sock|http://localhost/my-datasette/
The ProxyPreserveHost On directive ensures that the original Host: header from the incoming request is passed through to Datasette. Datasette needs this to correctly assemble links to other pages using the .absolute_url(request, path) method.","[""Deploying Datasette"", ""Running Datasette behind a proxy""]","[{""href"": ""https://httpd.apache.org/"", ""label"": ""Apache""}, {""href"": ""https://datasette-apache-proxy-demo.datasette.io/prefix/"", ""label"": ""datasette-apache-proxy-demo.datasette.io/prefix/""}, {""href"": ""https://github.com/simonw/datasette/tree/main/demos/apache-proxy"", ""label"": ""demos/apache-proxy""}, {""href"": ""https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypreservehost"", ""label"": ""ProxyPreserveHost On""}]"
changelog:id67,changelog,id67,0.38 (2020-03-08),"The Docker build of Datasette now uses SQLite 3.31.1, upgraded from 3.26. ( #695 )
datasette publish cloudrun now accepts an optional --memory=2Gi flag for setting the Cloud Run allocated memory to a value other than the default (256Mi). ( #694 )
Fixed bug where templates that shipped with plugins were sometimes not being correctly loaded. ( #697 )","[""Changelog""]","[{""href"": ""https://hub.docker.com/r/datasetteproject/datasette"", ""label"": ""Docker build""}, {""href"": ""https://github.com/simonw/datasette/issues/695"", ""label"": ""#695""}, {""href"": ""https://github.com/simonw/datasette/issues/694"", ""label"": ""#694""}, {""href"": ""https://github.com/simonw/datasette/issues/697"", ""label"": ""#697""}]"
changelog:id54,changelog,id54,0.47.2 (2020-08-12),Fixed an issue with the Docker image published to Docker Hub . ( #931 ),"[""Changelog""]","[{""href"": ""https://hub.docker.com/r/datasetteproject/datasette"", ""label"": ""published to Docker Hub""}, {""href"": ""https://github.com/simonw/datasette/issues/931"", ""label"": ""#931""}]"
installation:installation-docker,installation,installation-docker,Using Docker,"A Docker image containing the latest release of Datasette is published to Docker
Hub here: https://hub.docker.com/r/datasetteproject/datasette/
If you have Docker installed (for example with Docker for Mac on OS X) you can download and run this
image like so:
docker run -p 8001:8001 -v `pwd`:/mnt \
datasetteproject/datasette \
datasette -p 8001 -h 0.0.0.0 /mnt/fixtures.db
This will start an instance of Datasette running on your machine's port 8001,
serving the fixtures.db file in your current directory.
Now visit http://127.0.0.1:8001/ to access Datasette.
(You can download a copy of fixtures.db from
https://latest.datasette.io/fixtures.db )
To upgrade to the most recent release of Datasette, run the following:
docker pull datasetteproject/datasette","[""Installation"", ""Advanced installation options""]","[{""href"": ""https://hub.docker.com/r/datasetteproject/datasette/"", ""label"": ""https://hub.docker.com/r/datasetteproject/datasette/""}, {""href"": ""https://www.docker.com/docker-mac"", ""label"": ""Docker for Mac""}, {""href"": ""http://127.0.0.1:8001/"", ""label"": ""http://127.0.0.1:8001/""}, {""href"": ""https://latest.datasette.io/fixtures.db"", ""label"": ""https://latest.datasette.io/fixtures.db""}]"
internals:datasette-sign,internals,datasette-sign,".sign(value, namespace=""default"")","value - any serializable type
The value to be signed.
namespace - string, optional
An alternative namespace, see the itsdangerous salt documentation .
Utility method for signing values, such that you can safely pass data to and from an untrusted environment. This is a wrapper around the itsdangerous library.
This method returns a signed string, which can be decoded and verified using .unsign(value, namespace=""default"") .","[""Internals for plugins"", ""Datasette class""]","[{""href"": ""https://itsdangerous.palletsprojects.com/en/1.1.x/serializer/#the-salt"", ""label"": ""itsdangerous salt documentation""}, {""href"": ""https://itsdangerous.palletsprojects.com/"", ""label"": ""itsdangerous""}]"
changelog:id71,changelog,id71,0.35 (2020-02-04),"Added five new plugins and one new conversion tool to the The Datasette Ecosystem .
The Datasette class has a new render_template() method which can be used by plugins to render templates using Datasette's pre-configured Jinja templating library.
You can now execute SQL queries that start with a -- comment - thanks, Jay Graves ( #653 )","[""Changelog""]","[{""href"": ""https://jinja.palletsprojects.com/"", ""label"": ""Jinja""}, {""href"": ""https://github.com/simonw/datasette/pull/653"", ""label"": ""#653""}]"
changelog:id74,changelog,id74,0.32 (2019-11-14),"Datasette now renders templates using Jinja async mode . This means plugins can provide custom template functions that perform asynchronous actions, for example the new datasette-template-sql plugin which allows custom templates to directly execute SQL queries and render their results. ( #628 )","[""Changelog""]","[{""href"": ""https://jinja.palletsprojects.com/en/2.10.x/api/#async-support"", ""label"": ""Jinja async mode""}, {""href"": ""https://github.com/simonw/datasette-template-sql"", ""label"": ""datasette-template-sql""}, {""href"": ""https://github.com/simonw/datasette/issues/628"", ""label"": ""#628""}]"
plugin_hooks:plugin-hook-extra-template-vars,plugin_hooks,plugin-hook-extra-template-vars,"extra_template_vars(template, database, table, columns, view_name, request, datasette)","Extra template variables that should be made available in the rendered template context.
template - string
The template that is being rendered, e.g. database.html
database - string or None
The name of the database, or None if the page does not correspond to a database (e.g. the root page)
table - string or None
The name of the table, or None if the page does not correct to a table
columns - list of strings or None
The names of the database columns that will be displayed on this page. None if the page does not contain a table.
view_name - string
The name of the view being displayed. ( index , database , table , and row are the most important ones.)
request - Request object or None
The current HTTP request. This can be None if the request object is not available.
datasette - Datasette class
You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name)
This hook can return one of three different types:
Dictionary
If you return a dictionary its keys and values will be merged into the template context.
Function that returns a dictionary
If you return a function it will be executed. If it returns a dictionary those values will will be merged into the template context.
Function that returns an awaitable function that returns a dictionary
You can also return a function which returns an awaitable function which returns a dictionary.
Datasette runs Jinja2 in async mode , which means you can add awaitable functions to the template scope and they will be automatically awaited when they are rendered by the template.
Here's an example plugin that adds a ""user_agent"" variable to the template context containing the current request's User-Agent header:
@hookimpl
def extra_template_vars(request):
return {""user_agent"": request.headers.get(""user-agent"")}
This example returns an awaitable function which adds a list of hidden_table_names to the context:
@hookimpl
def extra_template_vars(datasette, database):
async def hidden_table_names():
if database:
db = datasette.databases[database]
return {
""hidden_table_names"": await db.hidden_table_names()
}
else:
return {}
return hidden_table_names
And here's an example which adds a sql_first(sql_query) function which executes a SQL statement and returns the first column of the first row of results:
@hookimpl
def extra_template_vars(datasette, database):
async def sql_first(sql, dbname=None):
dbname = (
dbname
or database
or next(iter(datasette.databases.keys()))
)
result = await datasette.execute(dbname, sql)
return result.rows[0][0]
return {""sql_first"": sql_first}
You can then use the new function in a template like so:
SQLite version: {{ sql_first(""select sqlite_version()"") }}
Examples: datasette-search-all , datasette-template-sql","[""Plugin hooks"", ""Page extras""]","[{""href"": ""https://jinja.palletsprojects.com/en/2.10.x/api/#async-support"", ""label"": ""async mode""}, {""href"": ""https://datasette.io/plugins/datasette-search-all"", ""label"": ""datasette-search-all""}, {""href"": ""https://datasette.io/plugins/datasette-template-sql"", ""label"": ""datasette-template-sql""}]"
internals:datasette-render-template,internals,datasette-render-template,"await .render_template(template, context=None, request=None)","template - string, list of strings or jinja2.Template
The template file to be rendered, e.g. my_plugin.html . Datasette will search for this file first in the --template-dir= location, if it was specified - then in the plugin's bundled templates and finally in Datasette's set of default templates.
If this is a list of template file names then the first one that exists will be loaded and rendered.
If this is a Jinja Template object it will be used directly.
context - None or a Python dictionary
The context variables to pass to the template.
request - request object or None
If you pass a Datasette request object here it will be made available to the template.
Renders a Jinja template using Datasette's preconfigured instance of Jinja and returns the resulting string. The template will have access to Datasette's default template functions and any functions that have been made available by other plugins.","[""Internals for plugins"", ""Datasette class""]","[{""href"": ""https://jinja.palletsprojects.com/en/2.11.x/api/#jinja2.Template"", ""label"": ""Template object""}, {""href"": ""https://jinja.palletsprojects.com/en/2.11.x/"", ""label"": ""Jinja template""}]"
plugin_hooks:plugin-hook-jinja2-environment-from-request,plugin_hooks,plugin-hook-jinja2-environment-from-request,"jinja2_environment_from_request(datasette, request, env)","datasette - Datasette class
A Datasette instance.
request - Request object or None
The current HTTP request, if one is available.
env - Environment
The Jinja2 environment that will be used to render the current page.
This hook can be used to return a customized Jinja environment based on the incoming request.
If you want to run a single Datasette instance that serves different content for different domains, you can do so like this:
from datasette import hookimpl
from jinja2 import ChoiceLoader, FileSystemLoader
@hookimpl
def jinja2_environment_from_request(request, env):
if request and request.host == ""www.niche-museums.com"":
return env.overlay(
loader=ChoiceLoader(
[
FileSystemLoader(
""/mnt/niche-museums/templates""
),
env.loader,
]
),
enable_async=True,
)
return env
This uses the Jinja overlay() method to create a new environment identical to the default environment except for having a different template loader, which first looks in the /mnt/niche-museums/templates directory before falling back on the default loader.","[""Plugin hooks""]","[{""href"": ""https://jinja.palletsprojects.com/en/3.0.x/api/#jinja2.Environment"", ""label"": ""Jinja environment""}, {""href"": ""https://jinja.palletsprojects.com/en/3.0.x/api/#jinja2.Environment.overlay"", ""label"": ""overlay() method""}]"
changelog:latest-datasette-io,changelog,latest-datasette-io,latest.datasette.io,"Every commit to Datasette master is now automatically deployed by Travis CI to
https://latest.datasette.io/ - ensuring there is always a live demo of the
latest version of the software.
The demo uses the fixtures from our
unit tests, ensuring it demonstrates the same range of functionality that is
covered by the tests.
You can see how the deployment mechanism works in our .travis.yml file.","[""Changelog"", ""0.23 (2018-06-18)""]","[{""href"": ""https://latest.datasette.io/"", ""label"": ""https://latest.datasette.io/""}, {""href"": ""https://github.com/simonw/datasette/blob/master/tests/fixtures.py"", ""label"": ""the fixtures""}, {""href"": ""https://github.com/simonw/datasette/blob/master/.travis.yml"", ""label"": "".travis.yml""}]"
authentication:permissions-view-instance,authentication,permissions-view-instance,view-instance,"Top level permission - Actor is allowed to view any pages within this instance, starting at https://latest.datasette.io/
Default allow .","[""Authentication and permissions"", ""Built-in permissions""]","[{""href"": ""https://latest.datasette.io/"", ""label"": ""https://latest.datasette.io/""}]"
contributing:contributing-continuous-deployment,contributing,contributing-continuous-deployment,Continuously deployed demo instances,"The demo instance at latest.datasette.io is re-deployed automatically to Google Cloud Run for every push to main that passes the test suite. This is implemented by the GitHub Actions workflow at .github/workflows/deploy-latest.yml .
Specific branches can also be set to automatically deploy by adding them to the on: push: branches block at the top of the workflow YAML file. Branches configured in this way will be deployed to a new Cloud Run service whether or not their tests pass.
The Cloud Run URL for a branch demo can be found in the GitHub Actions logs.","[""Contributing""]","[{""href"": ""https://latest.datasette.io/"", ""label"": ""latest.datasette.io""}, {""href"": ""https://github.com/simonw/datasette/blob/main/.github/workflows/deploy-latest.yml"", ""label"": "".github/workflows/deploy-latest.yml""}]"
authentication:allowdebugview,authentication,allowdebugview,The /-/allow-debug tool,"The /-/allow-debug tool lets you try out different ""action"" blocks against different ""actor"" JSON objects. You can try that out here: https://latest.datasette.io/-/allow-debug","[""Authentication and permissions"", ""Permissions""]","[{""href"": ""https://latest.datasette.io/-/allow-debug"", ""label"": ""https://latest.datasette.io/-/allow-debug""}]"
authentication:authentication-permissions-allow,authentication,authentication-permissions-allow,"Defining permissions with ""allow"" blocks","The standard way to define permissions in Datasette is to use an ""allow"" block in the datasette.yaml file . This is a JSON document describing which actors are allowed to perform a permission.
The most basic form of allow block is this ( allow demo , deny demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow:
id: root
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
This will match any actors with an ""id"" property of ""root"" - for example, an actor that looks like this:
{
""id"": ""root"",
""name"": ""Root User""
}
An allow block can specify ""deny all"" using false ( demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow: false
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
An ""allow"" of true allows all access ( demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow: true
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
Allow keys can provide a list of values. These will match any actor that has any of those values ( allow demo , deny demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow:
id:
- simon
- cleopaws
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
This will match any actor with an ""id"" of either ""simon"" or ""cleopaws"" .
Actors can have properties that feature a list of values. These will be matched against the list of values in an allow block. Consider the following actor:
{
""id"": ""simon"",
""roles"": [""staff"", ""developer""]
}
This allow block will provide access to any actor that has ""developer"" as one of their roles ( allow demo , deny demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow:
roles:
- developer
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
Note that ""roles"" is not a concept that is baked into Datasette - it's a convention that plugins can choose to implement and act on.
If you want to provide access to any actor with a value for a specific key, use ""*"" . For example, to match any logged-in user specify the following ( allow demo , deny demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow:
id: ""*""
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
You can specify that only unauthenticated actors (from anonymous HTTP requests) should be allowed access using the special ""unauthenticated"": true key in an allow block ( allow demo , deny demo ):
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow:
unauthenticated: true
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
Allow keys act as an ""or"" mechanism. An actor will be able to execute the query if any of their JSON properties match any of the values in the corresponding lists in the allow block. The following block will allow users with either a role of ""ops"" OR users who have an id of ""simon"" or ""cleopaws"" :
[[[cog
from metadata_doc import config_example
import textwrap
config_example(cog, textwrap.dedent(
""""""
allow:
id:
- simon
- cleopaws
role: ops
"""""").strip(),
""YAML"", ""JSON""
)
]]]
[[[end]]]
Demo for cleopaws , demo for ops role , demo for an actor matching neither rule .","[""Authentication and permissions"", ""Permissions""]","[{""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%22id%22%3A+%22root%22%7D&allow=%7B%0D%0A++++++++%22id%22%3A+%22root%22%0D%0A++++%7D"", ""label"": ""allow demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%22id%22%3A+%22trevor%22%7D&allow=%7B%0D%0A++++++++%22id%22%3A+%22root%22%0D%0A++++%7D"", ""label"": ""deny demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22root%22%0D%0A%7D&allow=false"", ""label"": ""demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22root%22%0D%0A%7D&allow=true"", ""label"": ""demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22cleopaws%22%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%5B%0D%0A++++++++%22simon%22%2C%0D%0A++++++++%22cleopaws%22%0D%0A++++%5D%0D%0A%7D"", ""label"": ""allow demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22pancakes%22%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%5B%0D%0A++++++++%22simon%22%2C%0D%0A++++++++%22cleopaws%22%0D%0A++++%5D%0D%0A%7D"", ""label"": ""deny demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22simon%22%2C%0D%0A++++%22roles%22%3A+%5B%0D%0A++++++++%22staff%22%2C%0D%0A++++++++%22developer%22%0D%0A++++%5D%0D%0A%7D&allow=%7B%0D%0A++++%22roles%22%3A+%5B%0D%0A++++++++%22developer%22%0D%0A++++%5D%0D%0A%7D"", ""label"": ""allow demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22cleopaws%22%2C%0D%0A++++%22roles%22%3A+%5B%22dog%22%5D%0D%0A%7D&allow=%7B%0D%0A++++%22roles%22%3A+%5B%0D%0A++++++++%22developer%22%0D%0A++++%5D%0D%0A%7D"", ""label"": ""deny demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22simon%22%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%22*%22%0D%0A%7D"", ""label"": ""allow demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22bot%22%3A+%22readme-bot%22%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%22*%22%0D%0A%7D"", ""label"": ""deny demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=null&allow=%7B%0D%0A++++%22unauthenticated%22%3A+true%0D%0A%7D"", ""label"": ""allow demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22hello%22%0D%0A%7D&allow=%7B%0D%0A++++%22unauthenticated%22%3A+true%0D%0A%7D"", ""label"": ""deny demo""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22cleopaws%22%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%5B%0D%0A++++++++%22simon%22%2C%0D%0A++++++++%22cleopaws%22%0D%0A++++%5D%2C%0D%0A++++%22role%22%3A+%22ops%22%0D%0A%7D"", ""label"": ""Demo for cleopaws""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22trevor%22%2C%0D%0A++++%22role%22%3A+%5B%0D%0A++++++++%22ops%22%2C%0D%0A++++++++%22staff%22%0D%0A++++%5D%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%5B%0D%0A++++++++%22simon%22%2C%0D%0A++++++++%22cleopaws%22%0D%0A++++%5D%2C%0D%0A++++%22role%22%3A+%22ops%22%0D%0A%7D"", ""label"": ""demo for ops role""}, {""href"": ""https://latest.datasette.io/-/allow-debug?actor=%7B%0D%0A++++%22id%22%3A+%22percy%22%2C%0D%0A++++%22role%22%3A+%5B%0D%0A++++++++%22staff%22%0D%0A++++%5D%0D%0A%7D&allow=%7B%0D%0A++++%22id%22%3A+%5B%0D%0A++++++++%22simon%22%2C%0D%0A++++++++%22cleopaws%22%0D%0A++++%5D%2C%0D%0A++++%22role%22%3A+%22ops%22%0D%0A%7D"", ""label"": ""demo for an actor matching neither rule""}]"
introspection:jsondataview-config,introspection,jsondataview-config,/-/config,"Shows the configuration for this instance of Datasette. This is generally the contents of the datasette.yaml or datasette.json file, which can include plugin configuration as well. Config example :
{
""settings"": {
""template_debug"": true,
""trace_debug"": true,
""force_https_urls"": true
}
}
Any keys that include the one of the following substrings in their names will be returned as redacted *** output, to help avoid accidentally leaking private configuration information: secret , key , password , token , hash , dsn .","[""Introspection""]","[{""href"": ""https://latest.datasette.io/-/config"", ""label"": ""Config example""}]"
introspection:jsondataview-databases,introspection,jsondataview-databases,/-/databases,"Shows currently attached databases. Databases example :
[
{
""hash"": null,
""is_memory"": false,
""is_mutable"": true,
""name"": ""fixtures"",
""path"": ""fixtures.db"",
""size"": 225280
}
]","[""Introspection""]","[{""href"": ""https://latest.datasette.io/-/databases"", ""label"": ""Databases example""}]"
introspection:jsondataview-threads,introspection,jsondataview-threads,/-/threads,"Shows details of threads and asyncio tasks. Threads example :
{
""num_threads"": 2,
""threads"": [
{
""daemon"": false,
""ident"": 4759197120,
""name"": ""MainThread""
},
{
""daemon"": true,
""ident"": 123145319682048,
""name"": ""Thread-1""
},
],
""num_tasks"": 3,
""tasks"": [
"" cb=[set.discard()]>"",
"" wait_for=()]> cb=[run_until_complete..()]>"",
"" wait_for=()]>>""
]
}","[""Introspection""]","[{""href"": ""https://latest.datasette.io/-/threads"", ""label"": ""Threads example""}]"
introspection:jsondataview-versions,introspection,jsondataview-versions,/-/versions,"Shows the version of Datasette, Python and SQLite. Versions example :
{
""datasette"": {
""version"": ""0.60""
},
""python"": {
""full"": ""3.8.12 (default, Dec 21 2021, 10:45:09) \n[GCC 10.2.1 20210110]"",
""version"": ""3.8.12""
},
""sqlite"": {
""extensions"": {
""json1"": null
},
""fts_versions"": [
""FTS5"",
""FTS4"",
""FTS3""
],
""compile_options"": [
""COMPILER=gcc-6.3.0 20170516"",
""ENABLE_FTS3"",
""ENABLE_FTS4"",
""ENABLE_FTS5"",
""ENABLE_JSON1"",
""ENABLE_RTREE"",
""THREADSAFE=1""
],
""version"": ""3.37.0""
}
}","[""Introspection""]","[{""href"": ""https://latest.datasette.io/-/versions"", ""label"": ""Versions example""}]"
settings:setting-template-debug,settings,setting-template-debug,template_debug,"This setting enables template context debug mode, which is useful to help understand what variables are available to custom templates when you are writing them.
Enable it like this:
datasette mydatabase.db --setting template_debug 1
Now you can add ?_context=1 or &_context=1 to any Datasette page to see the context that was passed to that template.
Some examples:
https://latest.datasette.io/?_context=1
https://latest.datasette.io/fixtures?_context=1
https://latest.datasette.io/fixtures/roadside_attractions?_context=1","[""Settings"", ""Settings""]","[{""href"": ""https://latest.datasette.io/?_context=1"", ""label"": ""https://latest.datasette.io/?_context=1""}, {""href"": ""https://latest.datasette.io/fixtures?_context=1"", ""label"": ""https://latest.datasette.io/fixtures?_context=1""}, {""href"": ""https://latest.datasette.io/fixtures/roadside_attractions?_context=1"", ""label"": ""https://latest.datasette.io/fixtures/roadside_attractions?_context=1""}]"
settings:setting-trace-debug,settings,setting-trace-debug,trace_debug,"This setting enables appending ?_trace=1 to any page in order to see the SQL queries and other trace information that was used to generate that page.
Enable it like this:
datasette mydatabase.db --setting trace_debug 1
Some examples:
https://latest.datasette.io/?_trace=1
https://latest.datasette.io/fixtures/roadside_attractions?_trace=1
See datasette.tracer for details on how to hook into this mechanism as a plugin author.","[""Settings"", ""Settings""]","[{""href"": ""https://latest.datasette.io/?_trace=1"", ""label"": ""https://latest.datasette.io/?_trace=1""}, {""href"": ""https://latest.datasette.io/fixtures/roadside_attractions?_trace=1"", ""label"": ""https://latest.datasette.io/fixtures/roadside_attractions?_trace=1""}]"
sql_queries:id3,sql_queries,id3,Cross-database queries,"SQLite has the ability to run queries that join across multiple databases. Up to ten databases can be attached to a single SQLite connection and queried together.
Datasette can execute joins across multiple databases if it is started with the --crossdb option:
datasette fixtures.db extra_database.db --crossdb
If it is started in this way, the /_memory page can be used to execute queries that join across multiple databases.
References to tables in attached databases should be preceded by the database name and a period.
For example, this query will show a list of tables across both of the above databases:
select
'fixtures' as database, *
from
[fixtures].sqlite_master
union
select
'extra_database' as database, *
from
[extra_database].sqlite_master
Try that out here .","[""Running SQL queries""]","[{""href"": ""https://latest.datasette.io/_memory?sql=select%0D%0A++%27fixtures%27+as+database%2C+*%0D%0Afrom%0D%0A++%5Bfixtures%5D.sqlite_master%0D%0Aunion%0D%0Aselect%0D%0A++%27extra_database%27+as+database%2C+*%0D%0Afrom%0D%0A++%5Bextra_database%5D.sqlite_master"", ""label"": ""Try that out here""}]"
authentication:permissions-view-database,authentication,permissions-view-database,view-database,"Actor is allowed to view a database page, e.g. https://latest.datasette.io/fixtures
resource - string
The name of the database
Default allow .","[""Authentication and permissions"", ""Built-in permissions""]","[{""href"": ""https://latest.datasette.io/fixtures"", ""label"": ""https://latest.datasette.io/fixtures""}]"
authentication:authentication-permissions-execute-sql,authentication,authentication-permissions-execute-sql,Controlling the ability to execute arbitrary SQL,"Datasette defaults to allowing any site visitor to execute their own custom SQL queries, for example using the form on the database page or by appending a ?_where= parameter to the table page like this .
Access to this ability is controlled by the execute-sql permission.
The easiest way to disable arbitrary SQL queries is using the default_allow_sql setting when you first start Datasette running.
You can alternatively use an ""allow_sql"" block to control who is allowed to execute arbitrary SQL queries.
To prevent any user from executing arbitrary SQL queries, use this:
[[[cog
config_example(cog, """"""
allow_sql: false
"""""")
]]]
[[[end]]]
To enable just the root user to execute SQL for all databases in your instance, use the following:
[[[cog
config_example(cog, """"""
allow_sql:
id: root
"""""")
]]]
[[[end]]]
To limit this ability for just one specific database, use this:
[[[cog
config_example(cog, """"""
databases:
mydatabase:
allow_sql:
id: root
"""""")
]]]
[[[end]]]","[""Authentication and permissions"", ""Access permissions in ""]","[{""href"": ""https://latest.datasette.io/fixtures"", ""label"": ""the database page""}, {""href"": ""https://latest.datasette.io/fixtures/facetable?_where=_city_id=1"", ""label"": ""like this""}]"
authentication:permissions-view-database-download,authentication,permissions-view-database-download,view-database-download,"Actor is allowed to download a database, e.g. https://latest.datasette.io/fixtures.db
resource - string
The name of the database
Default allow .","[""Authentication and permissions"", ""Built-in permissions""]","[{""href"": ""https://latest.datasette.io/fixtures.db"", ""label"": ""https://latest.datasette.io/fixtures.db""}]"
changelog:miscellaneous,changelog,miscellaneous,Miscellaneous,"Got JSON data in one of your columns? Use the new ?_json=COLNAME argument
to tell Datasette to return that JSON value directly rather than encoding it
as a string.
If you just want an array of the first value of each row, use the new
?_shape=arrayfirst option - example .","[""Changelog"", ""0.23 (2018-06-18)""]","[{""href"": ""https://latest.datasette.io/fixtures.json?sql=select+neighborhood+from+facetable+order+by+pk+limit+101&_shape=arrayfirst"", ""label"": ""example""}]"
binary_data:binary,binary_data,binary,Binary data,"SQLite tables can contain binary data in BLOB columns.
Datasette includes special handling for these binary values. The Datasette interface detects binary values and provides a link to download their content, for example on https://latest.datasette.io/fixtures/binary_data
Binary data is represented in .json exports using Base64 encoding.
https://latest.datasette.io/fixtures/binary_data.json?_shape=array
[
{
""rowid"": 1,
""data"": {
""$base64"": true,
""encoded"": ""FRwCx60F/g==""
}
},
{
""rowid"": 2,
""data"": {
""$base64"": true,
""encoded"": ""FRwDx60F/g==""
}
},
{
""rowid"": 3,
""data"": null
}
]",[],"[{""href"": ""https://latest.datasette.io/fixtures/binary_data"", ""label"": ""https://latest.datasette.io/fixtures/binary_data""}, {""href"": ""https://latest.datasette.io/fixtures/binary_data.json?_shape=array"", ""label"": ""https://latest.datasette.io/fixtures/binary_data.json?_shape=array""}]"
binary_data:binary-linking,binary_data,binary-linking,Linking to binary downloads,"The .blob output format is used to return binary data. It requires a _blob_column= query string argument specifying which BLOB column should be downloaded, for example:
https://latest.datasette.io/fixtures/binary_data/1.blob?_blob_column=data
This output format can also be used to return binary data from an arbitrary SQL query. Since such queries do not specify an exact row, an additional ?_blob_hash= parameter can be used to specify the SHA-256 hash of the value that is being linked to.
Consider the query select data from binary_data - demonstrated here .
That page links to the binary value downloads. Those links look like this:
https://latest.datasette.io/fixtures.blob?sql=select+data+from+binary_data&_blob_column=data&_blob_hash=f3088978da8f9aea479ffc7f631370b968d2e855eeb172bea7f6c7a04262bb6d
These .blob links are also returned in the .csv exports Datasette provides for binary tables and queries, since the CSV format does not have a mechanism for representing binary data.","[""Binary data""]","[{""href"": ""https://latest.datasette.io/fixtures/binary_data/1.blob?_blob_column=data"", ""label"": ""https://latest.datasette.io/fixtures/binary_data/1.blob?_blob_column=data""}, {""href"": ""https://latest.datasette.io/fixtures?sql=select+data+from+binary_data"", ""label"": ""demonstrated here""}, {""href"": ""https://latest.datasette.io/fixtures.blob?sql=select+data+from+binary_data&_blob_column=data&_blob_hash=f3088978da8f9aea479ffc7f631370b968d2e855eeb172bea7f6c7a04262bb6d"", ""label"": ""https://latest.datasette.io/fixtures.blob?sql=select+data+from+binary_data&_blob_column=data&_blob_hash=f3088978da8f9aea479ffc7f631370b968d2e855eeb172bea7f6c7a04262bb6d""}]"
authentication:permissions-view-table,authentication,permissions-view-table,view-table,"Actor is allowed to view a table (or view) page, e.g. https://latest.datasette.io/fixtures/complex_foreign_keys
resource - tuple: (string, string)
The name of the database, then the name of the table
Default allow .","[""Authentication and permissions"", ""Built-in permissions""]","[{""href"": ""https://latest.datasette.io/fixtures/complex_foreign_keys"", ""label"": ""https://latest.datasette.io/fixtures/complex_foreign_keys""}]"
csv_export:id1,csv_export,id1,CSV export,"Any Datasette table, view or custom SQL query can be exported as CSV.
To obtain the CSV representation of the table you are looking, click the ""this
data as CSV"" link.
You can also use the advanced export form for more control over the resulting
file, which looks like this and has the following options:
download file - instead of displaying CSV in your browser, this forces
your browser to download the CSV to your downloads directory.
expand labels - if your table has any foreign key references this option
will cause the CSV to gain additional COLUMN_NAME_label columns with a
label for each foreign key derived from the linked table. In this example
the city_id column is accompanied by a city_id_label column.
stream all rows - by default CSV files only contain the first
max_returned_rows records. This option will cause Datasette to
loop through every matching record and return them as a single CSV file.
You can try that out on https://latest.datasette.io/fixtures/facetable?_size=4",[],"[{""href"": ""https://latest.datasette.io/fixtures/facetable.csv?_labels=on&_size=max"", ""label"": ""In this example""}, {""href"": ""https://latest.datasette.io/fixtures/facetable?_size=4"", ""label"": ""https://latest.datasette.io/fixtures/facetable?_size=4""}]"
facets:id2,facets,id2,Facet by JSON array,"If your SQLite installation provides the json1 extension (you can check using /-/versions ) Datasette will automatically detect columns that contain JSON arrays of values and offer a faceting interface against those columns.
This is useful for modelling things like tags without needing to break them out into a new table.
Example here: latest.datasette.io/fixtures/facetable?_facet_array=tags","[""Facets""]","[{""href"": ""https://latest.datasette.io/fixtures/facetable?_facet_array=tags"", ""label"": ""latest.datasette.io/fixtures/facetable?_facet_array=tags""}]"
facets:id3,facets,id3,Facet by date,"If Datasette finds any columns that contain dates in the first 100 values, it will offer a faceting interface against the dates of those values.
This works especially well against timestamp values such as 2019-03-01 12:44:00 .
Example here: latest.datasette.io/fixtures/facetable?_facet_date=created","[""Facets""]","[{""href"": ""https://latest.datasette.io/fixtures/facetable?_facet_date=created"", ""label"": ""latest.datasette.io/fixtures/facetable?_facet_date=created""}]"
internals:internals-tracer,internals,internals-tracer,datasette.tracer,"Running Datasette with --setting trace_debug 1 enables trace debug output, which can then be viewed by adding ?_trace=1 to the query string for any page.
You can see an example of this at the bottom of latest.datasette.io/fixtures/facetable?_trace=1 . The JSON output shows full details of every SQL query that was executed to generate the page.
The datasette-pretty-traces plugin can be installed to provide a more readable display of this information. You can see a demo of that here .
You can add your own custom traces to the JSON output using the trace() context manager. This takes a string that identifies the type of trace being recorded, and records any keyword arguments as additional JSON keys on the resulting trace object.
The start and end time, duration and a traceback of where the trace was executed will be automatically attached to the JSON object.
This example uses trace to record the start, end and duration of any HTTP GET requests made using the function:
from datasette.tracer import trace
import httpx
async def fetch_url(url):
with trace(""fetch-url"", url=url):
async with httpx.AsyncClient() as client:
return await client.get(url)","[""Internals for plugins""]","[{""href"": ""https://latest.datasette.io/fixtures/facetable?_trace=1"", ""label"": ""latest.datasette.io/fixtures/facetable?_trace=1""}, {""href"": ""https://datasette.io/plugins/datasette-pretty-traces"", ""label"": ""datasette-pretty-traces""}, {""href"": ""https://latest-with-plugins.datasette.io/github/commits?_trace=1"", ""label"": ""a demo of that here""}]"
changelog:writable-canned-queries,changelog,writable-canned-queries,Writable canned queries,"Datasette's Canned queries feature lets you define SQL queries in metadata.json which can then be executed by users visiting a specific URL. https://latest.datasette.io/fixtures/neighborhood_search for example.
Canned queries were previously restricted to SELECT , but Datasette 0.44 introduces the ability for canned queries to execute INSERT or UPDATE queries as well, using the new ""write"": true property ( #800 ):
{
""databases"": {
""dogs"": {
""queries"": {
""add_name"": {
""sql"": ""INSERT INTO names (name) VALUES (:name)"",
""write"": true
}
}
}
}
}
See Writable canned queries for more details.","[""Changelog"", ""0.44 (2020-06-11)""]","[{""href"": ""https://latest.datasette.io/fixtures/neighborhood_search"", ""label"": ""https://latest.datasette.io/fixtures/neighborhood_search""}, {""href"": ""https://github.com/simonw/datasette/issues/800"", ""label"": ""#800""}]"
sql_queries:canned-queries-named-parameters,sql_queries,canned-queries-named-parameters,Canned query parameters,"Canned queries support named parameters, so if you include those in the SQL you will then be able to enter them using the form fields on the canned query page or by adding them to the URL. This means canned queries can be used to create custom JSON APIs based on a carefully designed SQL statement.
Here's an example of a canned query with a named parameter:
select neighborhood, facet_cities.name, state
from facetable
join facet_cities on facetable.city_id = facet_cities.id
where neighborhood like '%' || :text || '%'
order by neighborhood;
In the canned query configuration looks like this:
[[[cog
config_example(cog, """"""
databases:
fixtures:
queries:
neighborhood_search:
title: Search neighborhoods
sql: |-
select neighborhood, facet_cities.name, state
from facetable
join facet_cities on facetable.city_id = facet_cities.id
where neighborhood like '%' || :text || '%'
order by neighborhood
"""""")
]]]
[[[end]]]
Note that we are using SQLite string concatenation here - the || operator - to add wildcard % characters to the string provided by the user.
You can try this canned query out here:
https://latest.datasette.io/fixtures/neighborhood_search?text=town
In this example the :text named parameter is automatically extracted from the query using a regular expression.
You can alternatively provide an explicit list of named parameters using the ""params"" key, like this:
[[[cog
config_example(cog, """"""
databases:
fixtures:
queries:
neighborhood_search:
title: Search neighborhoods
params:
- text
sql: |-
select neighborhood, facet_cities.name, state
from facetable
join facet_cities on facetable.city_id = facet_cities.id
where neighborhood like '%' || :text || '%'
order by neighborhood
"""""")
]]]
[[[end]]]","[""Running SQL queries"", ""Canned queries""]","[{""href"": ""https://latest.datasette.io/fixtures/neighborhood_search?text=town"", ""label"": ""https://latest.datasette.io/fixtures/neighborhood_search?text=town""}]"
authentication:permissions-view-query,authentication,permissions-view-query,view-query,"Actor is allowed to view (and execute) a canned query page, e.g. https://latest.datasette.io/fixtures/pragma_cache_size - this includes executing Writable canned queries .
resource - tuple: (string, string)
The name of the database, then the name of the canned query
Default allow .","[""Authentication and permissions"", ""Built-in permissions""]","[{""href"": ""https://latest.datasette.io/fixtures/pragma_cache_size"", ""label"": ""https://latest.datasette.io/fixtures/pragma_cache_size""}]"
metadata:metadata-column-descriptions,metadata,metadata-column-descriptions,Column descriptions,"You can include descriptions for your columns by adding a ""columns"": {""name-of-column"": ""description-of-column""} block to your table metadata:
[[[cog
metadata_example(cog, {
""databases"": {
""database1"": {
""tables"": {
""example_table"": {
""columns"": {
""column1"": ""Description of column 1"",
""column2"": ""Description of column 2""
}
}
}
}
}
})
]]]
[[[end]]]
These will be displayed at the top of the table page, and will also show in the cog menu for each column.
You can see an example of how these look at latest.datasette.io/fixtures/roadside_attractions .","[""Metadata""]","[{""href"": ""https://latest.datasette.io/fixtures/roadside_attractions"", ""label"": ""latest.datasette.io/fixtures/roadside_attractions""}]"
changelog:through-for-joins-through-many-to-many-tables,changelog,through-for-joins-through-many-to-many-tables,?_through= for joins through many-to-many tables,"The new ?_through={json} argument to the Table view allows records to be filtered based on a many-to-many relationship. See Special table arguments for full documentation - here's an example . ( #355 )
This feature was added to help support facet by many-to-many , which isn't quite ready yet but will be coming in the next Datasette release.","[""Changelog"", ""0.29 (2019-07-07)""]","[{""href"": ""https://latest.datasette.io/fixtures/roadside_attractions?_through={%22table%22:%22roadside_attraction_characteristics%22,%22column%22:%22characteristic_id%22,%22value%22:%221%22}"", ""label"": ""an example""}, {""href"": ""https://github.com/simonw/datasette/issues/355"", ""label"": ""#355""}, {""href"": ""https://github.com/simonw/datasette/issues/551"", ""label"": ""facet by many-to-many""}]"
full_text_search:full-text-search-table-or-view,full_text_search,full-text-search-table-or-view,Configuring full-text search for a table or view,"If a table has a corresponding FTS table set up using the content= argument to CREATE VIRTUAL TABLE shown below, Datasette will detect it automatically and add a search interface to the table page for that table.
You can also manually configure which table should be used for full-text search using query string parameters or Metadata . You can set the associated FTS table for a specific table and you can also set one for a view - if you do that, the page for that SQL view will offer a search option.
Use ?_fts_table=x to over-ride the FTS table for a specific page. If the primary key was something other than rowid you can use ?_fts_pk=col to set that as well. This is particularly useful for views, for example:
https://latest.datasette.io/fixtures/searchable_view?_fts_table=searchable_fts&_fts_pk=pk
The fts_table metadata property can be used to specify an associated FTS table. If the primary key column in your table which was used to populate the FTS table is something other than rowid , you can specify the column to use with the fts_pk property.
The ""searchmode"": ""raw"" property can be used to default the table to accepting SQLite advanced search operators, as described in Advanced SQLite search queries .
Here is an example which enables full-text search (with SQLite advanced search operators) for a display_ads view which is defined against the ads table and hence needs to run FTS against the ads_fts table, using the id as the primary key:
[[[cog
from metadata_doc import metadata_example
metadata_example(cog, {
""databases"": {
""russian-ads"": {
""tables"": {
""display_ads"": {
""fts_table"": ""ads_fts"",
""fts_pk"": ""id"",
""searchmode"": ""raw""
}
}
}
}
})
]]]
[[[end]]]","[""Full-text search""]","[{""href"": ""https://latest.datasette.io/fixtures/searchable_view?_fts_table=searchable_fts&_fts_pk=pk"", ""label"": ""https://latest.datasette.io/fixtures/searchable_view?_fts_table=searchable_fts&_fts_pk=pk""}]"
authentication:authentication-permissions-table,authentication,authentication-permissions-table,Access to specific tables and views,"To limit access to the users table in your bakery.db database:
[[[cog
config_example(cog, """"""
databases:
bakery:
tables:
users:
allow:
id: '*'
"""""")
]]]
[[[end]]]
This works for SQL views as well - you can list their names in the ""tables"" block above in the same way as regular tables.
Restricting access to tables and views in this way will NOT prevent users from querying them using arbitrary SQL queries, like this for example.
If you are restricting access to specific tables you should also use the ""allow_sql"" block to prevent users from bypassing the limit with their own SQL queries - see Controlling the ability to execute arbitrary SQL .","[""Authentication and permissions"", ""Access permissions in ""]","[{""href"": ""https://latest.datasette.io/fixtures?sql=select+*+from+facetable"", ""label"": ""like this""}]"
authentication:permissions-execute-sql,authentication,permissions-execute-sql,execute-sql,"Actor is allowed to run arbitrary SQL queries against a specific database, e.g. https://latest.datasette.io/fixtures?sql=select+100
resource - string
The name of the database
Default allow . See also the default_allow_sql setting .","[""Authentication and permissions"", ""Built-in permissions""]","[{""href"": ""https://latest.datasette.io/fixtures?sql=select+100"", ""label"": ""https://latest.datasette.io/fixtures?sql=select+100""}]"
changelog:id13,changelog,id13,0.62 (2022-08-14),"Datasette can now run entirely in your browser using WebAssembly. Try out Datasette Lite , take a look at the code or read more about it in Datasette Lite: a server-side Python web application running in a browser .
Datasette now has a Discord community for questions and discussions about Datasette and its ecosystem of projects.","[""Changelog""]","[{""href"": ""https://lite.datasette.io/"", ""label"": ""Datasette Lite""}, {""href"": ""https://github.com/simonw/datasette-lite"", ""label"": ""at the code""}, {""href"": ""https://simonwillison.net/2022/May/4/datasette-lite/"", ""label"": ""Datasette Lite: a server-side Python web application running in a browser""}, {""href"": ""https://datasette.io/discord"", ""label"": ""Discord community""}]"
getting_started:getting-started-datasette-lite,getting_started,getting-started-datasette-lite,Datasette in your browser with Datasette Lite,"Datasette Lite is Datasette packaged using WebAssembly so that it runs entirely in your browser, no Python web application server required.
You can pass a URL to a CSV, SQLite or raw SQL file directly to Datasette Lite to explore that data in your browser.
This example link opens Datasette Lite and loads the SQL Murder Mystery example database from Northwestern University Knight Lab .","[""Getting started""]","[{""href"": ""https://lite.datasette.io/"", ""label"": ""Datasette Lite""}, {""href"": ""https://lite.datasette.io/?url=https%3A%2F%2Fraw.githubusercontent.com%2FNUKnightLab%2Fsql-mysteries%2Fmaster%2Fsql-murder-mystery.db#/sql-murder-mystery"", ""label"": ""example link""}, {""href"": ""https://github.com/NUKnightLab/sql-mysteries"", ""label"": ""Northwestern University Knight Lab""}]"
deploying:nginx-proxy-configuration,deploying,nginx-proxy-configuration,Nginx proxy configuration,"Here is an example of an nginx configuration file that will proxy traffic to Datasette:
daemon off;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /my-datasette {
proxy_pass http://127.0.0.1:8009/my-datasette;
proxy_set_header Host $host;
}
}
}
You can also use the --uds option to Datasette to listen on a Unix domain socket instead of a port, configuring the nginx upstream proxy like this:
daemon off;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /my-datasette {
proxy_pass http://datasette/my-datasette;
proxy_set_header Host $host;
}
}
upstream datasette {
server unix:/tmp/datasette.sock;
}
}
Then run Datasette with datasette --uds /tmp/datasette.sock path/to/database.db --setting base_url /my-datasette/ .","[""Deploying Datasette"", ""Running Datasette behind a proxy""]","[{""href"": ""https://nginx.org/"", ""label"": ""nginx""}]"
contributing:contributing-formatting-prettier,contributing,contributing-formatting-prettier,Prettier,"To install Prettier, install Node.js and then run the following in the root of your datasette repository checkout:
npm install
This will install Prettier in a node_modules directory. You can then check that your code matches the coding style like so:
npm run prettier -- --check
> prettier
> prettier 'datasette/static/*[!.min].js' ""--check""
Checking formatting...
[warn] datasette/static/plugins.js
[warn] Code style issues found in the above file(s). Forgot to run Prettier?
You can fix any problems by running:
npm run fix","[""Contributing"", ""Code formatting""]","[{""href"": ""https://nodejs.org/en/download/package-manager/"", ""label"": ""install Node.js""}]"
changelog:id30,changelog,id30,0.57 (2021-06-05),"This release fixes a reflected cross-site scripting security hole with the ?_trace=1 feature. You should upgrade to this version, or to Datasette 0.56.1, as soon as possible. ( #1360 )
In addition to the security fix, this release includes ?_col= and ?_nocol= options for controlling which columns are displayed for a table, ?_facet_size= for increasing the number of facet results returned, re-display of your SQL query should an error occur and numerous bug fixes.","[""Changelog""]","[{""href"": ""https://owasp.org/www-community/attacks/xss/#reflected-xss-attacks"", ""label"": ""reflected cross-site scripting""}, {""href"": ""https://github.com/simonw/datasette/issues/1360"", ""label"": ""#1360""}]"
changelog:id31,changelog,id31,0.56.1 (2021-06-05),"This release fixes a reflected cross-site scripting security hole with the ?_trace=1 feature. You should upgrade to this version, or to Datasette 0.57, as soon as possible. ( #1360 )","[""Changelog""]","[{""href"": ""https://owasp.org/www-community/attacks/xss/#reflected-xss-attacks"", ""label"": ""reflected cross-site scripting""}, {""href"": ""https://github.com/simonw/datasette/issues/1360"", ""label"": ""#1360""}]"
metadata:specifying-units-for-a-column,metadata,specifying-units-for-a-column,Specifying units for a column,"Datasette supports attaching units to a column, which will be used when displaying
values from that column. SI prefixes will be used where appropriate.
Column units are configured in the metadata like so:
[[[cog
metadata_example(cog, {
""databases"": {
""database1"": {
""tables"": {
""example_table"": {
""units"": {
""column1"": ""metres"",
""column2"": ""Hz""
}
}
}
}
}
})
]]]
[[[end]]]
Units are interpreted using Pint , and you can see the full list of available units in
Pint's unit registry . You can also add custom units to the metadata, which will be
registered with Pint:
[[[cog
metadata_example(cog, {
""custom_units"": [
""decibel = [] = dB""
]
})
]]]
[[[end]]]","[""Metadata""]","[{""href"": ""https://pint.readthedocs.io/"", ""label"": ""Pint""}, {""href"": ""https://github.com/hgrecco/pint/blob/master/pint/default_en.txt"", ""label"": ""unit registry""}, {""href"": ""http://pint.readthedocs.io/en/latest/defining.html"", ""label"": ""custom units""}]"
installation:installation-pipx,installation,installation-pipx,Using pipx,"pipx is a tool for installing Python software with all of its dependencies in an isolated environment, to ensure that they will not conflict with any other installed Python software.
If you use Homebrew on macOS you can install pipx like this:
brew install pipx
pipx ensurepath
Without Homebrew you can install it like so:
python3 -m pip install --user pipx
python3 -m pipx ensurepath
The pipx ensurepath command configures your shell to ensure it can find commands that have been installed by pipx - generally by making sure ~/.local/bin has been added to your PATH .
Once pipx is installed you can use it to install Datasette like this:
pipx install datasette
Then run datasette --version to confirm that it has been successfully installed.","[""Installation"", ""Advanced installation options""]","[{""href"": ""https://pipxproject.github.io/pipx/"", ""label"": ""pipx""}, {""href"": ""https://brew.sh/"", ""label"": ""Homebrew""}]"
plugins:id1,plugins,id1,Plugins,"Datasette's plugin system allows additional features to be implemented as Python
code (or front-end JavaScript) which can be wrapped up in a separate Python
package. The underlying mechanism uses pluggy .
See the Datasette plugins directory for a list of existing plugins, or take a look at the
datasette-plugin topic on GitHub.
Things you can do with plugins include:
Add visualizations to Datasette, for example
datasette-cluster-map and
datasette-vega .
Make new custom SQL functions available for use within Datasette, for example
datasette-haversine and
datasette-jellyfish .
Define custom output formats with custom extensions, for example datasette-atom and
datasette-ics .
Add template functions that can be called within your Jinja custom templates,
for example datasette-render-markdown .
Customize how database values are rendered in the Datasette interface, for example
datasette-render-binary and
datasette-pretty-json .
Customize how Datasette's authentication and permissions systems work, for example datasette-auth-passwords and
datasette-permissions-sql .",[],"[{""href"": ""https://pluggy.readthedocs.io/"", ""label"": ""pluggy""}, {""href"": ""https://datasette.io/plugins"", ""label"": ""Datasette plugins directory""}, {""href"": ""https://github.com/topics/datasette-plugin"", ""label"": ""datasette-plugin""}, {""href"": ""https://github.com/simonw/datasette-cluster-map"", ""label"": ""datasette-cluster-map""}, {""href"": ""https://github.com/simonw/datasette-vega"", ""label"": ""datasette-vega""}, {""href"": ""https://github.com/simonw/datasette-haversine"", ""label"": ""datasette-haversine""}, {""href"": ""https://github.com/simonw/datasette-jellyfish"", ""label"": ""datasette-jellyfish""}, {""href"": ""https://github.com/simonw/datasette-atom"", ""label"": ""datasette-atom""}, {""href"": ""https://github.com/simonw/datasette-ics"", ""label"": ""datasette-ics""}, {""href"": ""https://github.com/simonw/datasette-render-markdown#markdown-in-templates"", ""label"": ""datasette-render-markdown""}, {""href"": ""https://github.com/simonw/datasette-render-binary"", ""label"": ""datasette-render-binary""}, {""href"": ""https://github.com/simonw/datasette-pretty-json"", ""label"": ""datasette-pretty-json""}, {""href"": ""https://github.com/simonw/datasette-auth-passwords"", ""label"": ""datasette-auth-passwords""}, {""href"": ""https://github.com/simonw/datasette-permissions-sql"", ""label"": ""datasette-permissions-sql""}]"
plugin_hooks:id1,plugin_hooks,id1,Plugin hooks,"Datasette plugins use plugin hooks to customize Datasette's behavior. These hooks are powered by the pluggy plugin system.
Each plugin can implement one or more hooks using the @hookimpl decorator against a function named that matches one of the hooks documented on this page.
When you implement a plugin hook you can accept any or all of the parameters that are documented as being passed to that hook.
For example, you can implement the render_cell plugin hook like this even though the full documented hook signature is render_cell(row, value, column, table, database, datasette) :
@hookimpl
def render_cell(value, column):
if column == ""stars"":
return ""*"" * int(value)
List of plugin hooks
prepare_connection(conn, database, datasette)
prepare_jinja2_environment(env, datasette)
Page extras
extra_template_vars(template, database, table, columns, view_name, request, datasette)
extra_css_urls(template, database, table, columns, view_name, request, datasette)
extra_js_urls(template, database, table, columns, view_name, request, datasette)
extra_body_script(template, database, table, columns, view_name, request, datasette)
publish_subcommand(publish)
render_cell(row, value, column, table, database, datasette, request)
register_output_renderer(datasette)
register_routes(datasette)
register_commands(cli)
register_facet_classes()
register_permissions(datasette)
asgi_wrapper(datasette)
startup(datasette)
canned_queries(datasette, database, actor)
actor_from_request(datasette, request)
actors_from_ids(datasette, actor_ids)
jinja2_environment_from_request(datasette, request, env)
filters_from_request(request, database, table, datasette)
permission_allowed(datasette, actor, action, resource)
register_magic_parameters(datasette)
forbidden(datasette, request, message)
handle_exception(datasette, request, exception)
skip_csrf(datasette, scope)
get_metadata(datasette, key, database, table)
menu_links(datasette, actor, request)
Action hooks
table_actions(datasette, actor, database, table, request)
view_actions(datasette, actor, database, view, request)
query_actions(datasette, actor, database, query_name, request, sql, params)
row_actions(datasette, actor, request, database, table, row)
database_actions(datasette, actor, database, request)
homepage_actions(datasette, actor, request)
Template slots
top_homepage(datasette, request)
top_database(datasette, request, database)
top_table(datasette, request, database, table)
top_row(datasette, request, database, table, row)
top_query(datasette, request, database, sql)
top_canned_query(datasette, request, database, query_name)
Event tracking
track_event(datasette, event)
register_events(datasette)",[],"[{""href"": ""https://pluggy.readthedocs.io/"", ""label"": ""pluggy""}]"
plugin_hooks:plugin-hook-slots,plugin_hooks,plugin-hook-slots,Template slots,"The following set of plugin hooks can be used to return extra HTML content that will be inserted into the corresponding page, directly below the heading.
Multiple plugins can contribute content here. The order in which it is displayed can be controlled using Pluggy's call time order options .
Each of these plugin hooks can return either a string or an awaitable function that returns a string.","[""Plugin hooks""]","[{""href"": ""https://pluggy.readthedocs.io/en/stable/#call-time-order"", ""label"": ""call time order options""}]"
changelog:id14,changelog,id14,Features,"Datasette is now compatible with Pyodide . This is the enabling technology behind Datasette Lite . ( #1733 )
Database file downloads now implement conditional GET using ETags. ( #1739 )
HTML for facet results and suggested results has been extracted out into new templates _facet_results.html and _suggested_facets.html . Thanks, M. Nasimul Haque. ( #1759 )
Datasette now runs some SQL queries in parallel. This has limited impact on performance, see this research issue for details.
New --nolock option for ignoring file locks when opening read-only databases. ( #1744 )
Spaces in the database names in URLs are now encoded as + rather than ~20 . ( #1701 )
is now displayed as and is accompanied by tooltip showing ""2.3MB"". ( #1712 )
The base Docker image used by datasette publish cloudrun , datasette package and the official Datasette image has been upgraded to 3.10.6-slim-bullseye . ( #1768 )
Canned writable queries against immutable databases now show a warning message. ( #1728 )
datasette publish cloudrun has a new --timeout option which can be used to increase the time limit applied by the Google Cloud build environment. Thanks, Tim Sherratt. ( #1717 )
datasette publish cloudrun has new --min-instances and --max-instances options. ( #1779 )","[""Changelog"", ""0.62 (2022-08-14)""]","[{""href"": ""https://pyodide.org/"", ""label"": ""Pyodide""}, {""href"": ""https://lite.datasette.io/"", ""label"": ""Datasette Lite""}, {""href"": ""https://github.com/simonw/datasette/issues/1733"", ""label"": ""#1733""}, {""href"": ""https://github.com/simonw/datasette/issues/1739"", ""label"": ""#1739""}, {""href"": ""https://github.com/simonw/datasette/pull/1759"", ""label"": ""#1759""}, {""href"": ""https://github.com/simonw/datasette/issues/1727"", ""label"": ""this research issue""}, {""href"": ""https://github.com/simonw/datasette/issues/1744"", ""label"": ""#1744""}, {""href"": ""https://github.com/simonw/datasette/issues/1701"", ""label"": ""#1701""}, {""href"": ""https://github.com/simonw/datasette/issues/1712"", ""label"": ""#1712""}, {""href"": ""https://hub.docker.com/datasetteproject/datasette"", ""label"": ""official Datasette image""}, {""href"": ""https://github.com/simonw/datasette/issues/1768"", ""label"": ""#1768""}, {""href"": ""https://github.com/simonw/datasette/issues/1728"", ""label"": ""#1728""}, {""href"": ""https://github.com/simonw/datasette/pull/1717"", ""label"": ""#1717""}, {""href"": ""https://github.com/simonw/datasette/issues/1779"", ""label"": ""#1779""}]"