# sections

id: changelog:id26
page: changelog
ref: id26
title: 0.58.1 (2021-07-16)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/1231", "label": "#1231"}]
content:
Fix for an intermittent race condition caused by the  refresh_schemas()  internal function. ( #1231 )


id: changelog:id27
page: changelog
ref: id27
title: 0.58 (2021-07-14)
breadcrumbs: ["Changelog"]
content:
New  datasette --uds /tmp/datasette.sock  option for binding Datasette to a Unix domain socket, see  proxy documentation  ( #1388 ) 
                 
                 
                     "searchmode": "raw"  table metadata option for defaulting a table to executing SQLite full-text search syntax without first escaping it, see  Advanced SQLite search queries . ( #1389 ) 
                 
                 
                     New plugin hook:  get_metadata(datasette, key, database, table) , for returning custom metadata for an instance, database or table. Thanks, Brandon Roberts! ( #1384 ) 
                 
                 
                     New plugin hook:  skip_csrf(datasette, scope) , for opting out of CSRF protection based on the incoming request. ( #1377 ) 
                 
                 
                     The  menu_links() ,  table_actions()  and  database_actions()  plugin hooks all gained a new optional  request  argument providing access to the current request. ( #1371 ) 
                 
                 
                     Major performance improvement for Datasette faceting. ( #1394 ) 
                 
                 
                     Improved documentation for  Running Datasette behind a proxy  to recommend using  ProxyPreservehost On  with Apache. ( #1387 ) 
                 
                 
                     POST  requests to endpoints that do not support that HTTP verb now return a 405 error. 
                 
                 
                     db.path  can now be provided as a  pathlib.Path  object, useful when writing unit tests for plugins. Thanks, Chris Amico. ( #1365 )

references:
[{"href": "https://github.com/simonw/datasette/issues/1388", "label": "#1388"}, {"href": "https://github.com/simonw/datasette/issues/1389", "label": "#1389"}, {"href": "https://github.com/simonw/datasette/issues/1384", "label": "#1384"}, {"href": "https://github.com/simonw/datasette/issues/1377", "label": "#1377"}, {"href": "https://github.com/simonw/datasette/issues/1371", "label": "#1371"}, {"href": "https://github.com/simonw/datasette/issues/1394", "label": "#1394"}, {"href": "https://github.com/simonw/datasette/issues/1387", "label": "#1387"}, {"href": "https://github.com/simonw/datasette/issues/1365", "label": "#1365"}]


id: changelog:id28
page: changelog
ref: id28
title: 0.57.1 (2021-06-08)
breadcrumbs: ["Changelog"]
content:
Fixed visual display glitch with global navigation menu. ( #1367 ) 
                 
                 
                     No longer truncates the list of table columns displayed on the  /database  page. ( #1364 )

references:
[{"href": "https://github.com/simonw/datasette/issues/1367", "label": "#1367"}, {"href": "https://github.com/simonw/datasette/issues/1364", "label": "#1364"}]


id: changelog:id29
page: changelog
ref: id29
title: 0.57 (2021-06-05)
breadcrumbs: ["Changelog"]
content:
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.

references:
[{"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"}]


id: changelog:new-features
page: changelog
ref: new-features
title: New features
breadcrumbs: ["Changelog", "0.57 (2021-06-05)"]
content:
If an error occurs while executing a user-provided SQL query, that query is now re-displayed in an editable form along with the error message. ( #619 ) 
                     
                     
                         New  ?_col=  and  ?_nocol=  parameters to show and hide columns in a table, plus an interface for hiding and showing columns in the column cog menu. ( #615 ) 
                     
                     
                         A new  ?_facet_size=  parameter for customizing the number of facet results returned on a table or view page. ( #1332 ) 
                     
                     
                         ?_facet_size=max  sets that to the maximum, which defaults to 1,000 and is controlled by the the  max_returned_rows  setting. If facet results are truncated the … at the bottom of the facet list now links to this parameter. ( #1337 ) 
                     
                     
                         ?_nofacet=1  option to disable all facet calculations on a page, used as a performance optimization for CSV exports and  ?_shape=array/object . ( #1349 ,  #263 ) 
                     
                     
                         ?_nocount=1  option to disable full query result counts. ( #1353 ) 
                     
                     
                         ?_trace=1  debugging option is now controlled by the new  trace_debug  setting, which is turned off by default. ( #1359 )

references:
[{"href": "https://github.com/simonw/datasette/issues/619", "label": "#619"}, {"href": "https://github.com/simonw/datasette/issues/615", "label": "#615"}, {"href": "https://github.com/simonw/datasette/issues/1332", "label": "#1332"}, {"href": "https://github.com/simonw/datasette/issues/1337", "label": "#1337"}, {"href": "https://github.com/simonw/datasette/issues/1349", "label": "#1349"}, {"href": "https://github.com/simonw/datasette/issues/263", "label": "#263"}, {"href": "https://github.com/simonw/datasette/issues/1353", "label": "#1353"}, {"href": "https://github.com/simonw/datasette/issues/1359", "label": "#1359"}]


id: changelog:bug-fixes-and-other-improvements
page: changelog
ref: bug-fixes-and-other-improvements
title: Bug fixes and other improvements
breadcrumbs: ["Changelog", "0.57 (2021-06-05)"]
content:
Custom pages  now work correctly when combined with the  base_url  setting. ( #1238 ) 
                     
                     
                         Fixed intermittent error displaying the index page when the user did not have permission to access one of the tables. Thanks, Guy Freeman. ( #1305 ) 
                     
                     
                         Columns with the name "Link" are no longer incorrectly displayed in bold. ( #1308 ) 
                     
                     
                         Fixed error caused by tables with a single quote in their names. ( #1257 ) 
                     
                     
                         Updated dependencies:  pytest-asyncio ,  Black ,  jinja2 ,  aiofiles ,  click , and  itsdangerous . 
                     
                     
                         The official Datasette Docker image now supports  apt-get install . ( #1320 ) 
                     
                     
                         The Heroku runtime used by  datasette publish heroku  is now  python-3.8.10 .

references:
[{"href": "https://github.com/simonw/datasette/issues/1238", "label": "#1238"}, {"href": "https://github.com/simonw/datasette/issues/1305", "label": "#1305"}, {"href": "https://github.com/simonw/datasette/issues/1308", "label": "#1308"}, {"href": "https://github.com/simonw/datasette/issues/1257", "label": "#1257"}, {"href": "https://github.com/simonw/datasette/issues/1320", "label": "#1320"}]


id: changelog:id30
page: changelog
ref: id30
title: 0.56.1 (2021-06-05)
breadcrumbs: ["Changelog"]
content:
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 )

references:
[{"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"}]


id: changelog:id31
page: changelog
ref: id31
title: 0.56 (2021-03-28)
breadcrumbs: ["Changelog"]
content:
Documentation improvements, bug fixes and support for SpatiaLite 5. 
             
                 
                     The SQL editor can now be resized by dragging a handle. ( #1236 ) 
                 
                 
                     Fixed a bug with JSON faceting and the  __arraycontains  filter caused by tables with spaces in their names. ( #1239 ) 
                 
                 
                     Upgraded  httpx  dependency. ( #1005 ) 
                 
                 
                     JSON faceting is now suggested even if a column contains blank strings. ( #1246 ) 
                 
                 
                     New  datasette.add_memory_database()  method. ( #1247 ) 
                 
                 
                     The  Response.asgi_send()  method is now documented. ( #1266 ) 
                 
                 
                     The official Datasette Docker image now bundles SpatiaLite version 5. ( #1278 ) 
                 
                 
                     Fixed a  no such table: pragma_database_list  bug when running Datasette against SQLite versions prior to SQLite 3.16.0. ( #1276 ) 
                 
                 
                     HTML lists displayed in table cells are now styled correctly. Thanks, Bob Whitelock. ( #1141 ,  #1252 ) 
                 
                 
                     Configuration directory mode now correctly serves immutable databases that are listed in  inspect-data.json . Thanks Campbell Allen and Frankie Robertson. ( #1031 ,  #1229 )

references:
[{"href": "https://github.com/simonw/datasette/issues/1236", "label": "#1236"}, {"href": "https://github.com/simonw/datasette/issues/1239", "label": "#1239"}, {"href": "https://github.com/simonw/datasette/issues/1005", "label": "#1005"}, {"href": "https://github.com/simonw/datasette/issues/1246", "label": "#1246"}, {"href": "https://github.com/simonw/datasette/issues/1247", "label": "#1247"}, {"href": "https://github.com/simonw/datasette/issues/1266", "label": "#1266"}, {"href": "https://github.com/simonw/datasette/issues/1278", "label": "#1278"}, {"href": "https://github.com/simonw/datasette/issues/1276", "label": "#1276"}, {"href": "https://github.com/simonw/datasette/issues/1141", "label": "#1141"}, {"href": "https://github.com/simonw/datasette/pull/1252", "label": "#1252"}, {"href": "https://github.com/simonw/datasette/pull/1031", "label": "#1031"}, {"href": "https://github.com/simonw/datasette/pull/1229", "label": "#1229"}]


id: changelog:id32
page: changelog
ref: id32
title: 0.55 (2021-02-18)
breadcrumbs: ["Changelog"]
content:
Support for cross-database SQL queries and built-in support for serving via HTTPS. 
             
                 
                     The new  --crossdb  command-line option causes Datasette to attach up to ten database files to the same  /_memory  database connection. This enables cross-database SQL queries, including the ability to use joins and unions to combine data from tables that exist in different database files. See  Cross-database queries  for details. ( #283 ) 
                 
                 
                     --ssl-keyfile  and  --ssl-certfile  options can be used to specify a TLS certificate, allowing Datasette to serve traffic over  https://  without needing to run it behind a separate proxy. ( #1221 ) 
                 
                 
                     The  /:memory:  page has been renamed (and redirected) to  /_memory  for consistency with the new  /_internal  database introduced in Datasette 0.54. ( #1205 ) 
                 
                 
                     Added plugin testing documentation on  Using pdb for errors thrown inside Datasette . ( #1207 ) 
                 
                 
                     The  official Datasette Docker image  now uses Python 3.7.10, applying  the latest security fix  for that Python version. ( #1235 )

references:
[{"href": "https://github.com/simonw/datasette/issues/283", "label": "#283"}, {"href": "https://github.com/simonw/datasette/issues/1221", "label": "#1221"}, {"href": "https://github.com/simonw/datasette/issues/1205", "label": "#1205"}, {"href": "https://github.com/simonw/datasette/issues/1207", "label": "#1207"}, {"href": "https://hub.docker.com/r/datasetteproject/datasette", "label": "official Datasette Docker image"}, {"href": "https://www.python.org/downloads/release/python-3710/", "label": "the latest security fix"}, {"href": "https://github.com/simonw/datasette/issues/1235", "label": "#1235"}]


id: changelog:id33
page: changelog
ref: id33
title: 0.54.1 (2021-02-02)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/1214", "label": "#1214"}]
content:
Fixed a bug where  ?_search=  and  ?_sort=  parameters were incorrectly duplicated when the filter form on the table page was re-submitted. ( #1214 )


id: changelog:id34
page: changelog
ref: id34
title: 0.54 (2021-01-25)
breadcrumbs: ["Changelog"]
content:
The two big new features in this release are the  _internal  SQLite in-memory database storing details of all connected databases and tables, and support for JavaScript modules in plugins and additional scripts. 
             For additional commentary on this release, see  Datasette 0.54, the annotated release notes .

references:
[{"href": "https://simonwillison.net/2021/Jan/25/datasette/", "label": "Datasette 0.54, the annotated release notes"}]


id: changelog:the-internal-database
page: changelog
ref: the-internal-database
title: The _internal database
breadcrumbs: ["Changelog", "0.54 (2021-01-25)"]
content:
As part of ongoing work to help Datasette handle much larger numbers of connected databases and tables (see  Datasette Library ) Datasette now maintains an in-memory SQLite database with details of all of the attached databases, tables, columns, indexes and foreign keys. ( #1150 ) 
                 This will support future improvements such as a searchable, paginated homepage of all available tables. 
                 You can explore an example of this database by  signing in as root  to the  latest.datasette.io  demo instance and then navigating to  latest.datasette.io/_internal . 
                 Plugins can use these tables to introspect attached data in an efficient way. Plugin authors should note that this is not yet considered a stable interface, so any plugins that use this may need to make changes prior to Datasette 1.0 if the  _internal  table schemas change.

references:
[{"href": "https://github.com/simonw/datasette/issues/417", "label": "Datasette Library"}, {"href": "https://github.com/simonw/datasette/issues/1150", "label": "#1150"}, {"href": "https://latest.datasette.io/login-as-root", "label": "signing in as root"}, {"href": "https://latest.datasette.io/_internal", "label": "latest.datasette.io/_internal"}]


id: changelog:named-in-memory-database-support
page: changelog
ref: named-in-memory-database-support
title: Named in-memory database support
breadcrumbs: ["Changelog", "0.54 (2021-01-25)"]
references: [{"href": "https://github.com/simonw/datasette/issues/1151", "label": "#1151"}]
content:
As part of the work building the  _internal  database, Datasette now supports named in-memory databases that can be shared across multiple connections. This allows plugins to create in-memory databases which will persist data for the lifetime of the Datasette server process. ( #1151 ) 
                 The new  memory_name=  parameter to the  Database class  can be used to create named, shared in-memory databases.


id: changelog:javascript-modules
page: changelog
ref: javascript-modules
title: JavaScript modules
breadcrumbs: ["Changelog", "0.54 (2021-01-25)"]
content:
JavaScript modules  were introduced in ECMAScript 2015 and provide native browser support for the  import  and  export  keywords. 
                 To use modules, JavaScript needs to be included in  <script>  tags with a  type="module"  attribute. 
                 Datasette now has the ability to output  <script type="module">  in places where you may wish to take advantage of modules. The  extra_js_urls  option described in  Custom CSS and JavaScript  can now be used with modules, and module support is also available for the  extra_body_script()  plugin hook. ( #1186 ,  #1187 ) 
                 datasette-leaflet-freedraw  is the first example of a Datasette plugin that takes advantage of the new support for JavaScript modules. See  Drawing shapes on a map to query a SpatiaLite database  for more on this plugin.

references:
[{"href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules", "label": "JavaScript modules"}, {"href": "https://github.com/simonw/datasette/issues/1186", "label": "#1186"}, {"href": "https://github.com/simonw/datasette/issues/1187", "label": "#1187"}, {"href": "https://datasette.io/plugins/datasette-leaflet-freedraw", "label": "datasette-leaflet-freedraw"}, {"href": "https://simonwillison.net/2021/Jan/24/drawing-shapes-spatialite/", "label": "Drawing shapes on a map to query a SpatiaLite database"}]


id: changelog:code-formatting-with-black-and-prettier
page: changelog
ref: code-formatting-with-black-and-prettier
title: Code formatting with Black and Prettier
breadcrumbs: ["Changelog", "0.54 (2021-01-25)"]
content:
Datasette adopted  Black  for opinionated Python code formatting in June 2019. Datasette now also embraces  Prettier  for JavaScript formatting, which like Black is enforced by tests in continuous integration. Instructions for using these two tools can be found in the new section on  Code formatting  in the contributors documentation. ( #1167 )

references:
[{"href": "https://github.com/psf/black", "label": "Black"}, {"href": "https://prettier.io/", "label": "Prettier"}, {"href": "https://github.com/simonw/datasette/issues/1167", "label": "#1167"}]


id: changelog:other-changes
page: changelog
ref: other-changes
title: Other changes
breadcrumbs: ["Changelog", "0.54 (2021-01-25)"]
content:
Datasette can now open multiple database files with the same name, e.g. if you run  datasette path/to/one.db path/to/other/one.db . ( #509 ) 
                     
                     
                         datasette publish cloudrun  now sets  force_https_urls  for every deployment, fixing some incorrect  http://  links. ( #1178 ) 
                     
                     
                         Fixed a bug in the example nginx configuration in  Running Datasette behind a proxy . ( #1091 ) 
                     
                     
                         The  Datasette Ecosystem  documentation page has been reduced in size in favour of the  datasette.io   tools  and  plugins  directories. ( #1182 ) 
                     
                     
                         The request object now provides a  request.full_path  property, which returns the path including any query string. ( #1184 ) 
                     
                     
                         Better error message for disallowed  PRAGMA  clauses in SQL queries. ( #1185 ) 
                     
                     
                         datasette publish heroku  now deploys using  python-3.8.7 . 
                     
                     
                         New plugin testing documentation on  Testing outbound HTTP calls with pytest-httpx . ( #1198 ) 
                     
                     
                         All  ?_*  query string parameters passed to the table page are now persisted in hidden form fields, so parameters such as  ?_size=10  will be correctly passed to the next page when query filters are changed. ( #1194 ) 
                     
                     
                         Fixed a bug loading a database file called  test-database (1).sqlite . ( #1181 )

references:
[{"href": "https://github.com/simonw/datasette/issues/509", "label": "#509"}, {"href": "https://github.com/simonw/datasette/issues/1178", "label": "#1178"}, {"href": "https://github.com/simonw/datasette/issues/1091", "label": "#1091"}, {"href": "https://datasette.io/tools", "label": "tools"}, {"href": "https://datasette.io/plugins", "label": "plugins"}, {"href": "https://github.com/simonw/datasette/issues/1182", "label": "#1182"}, {"href": "https://github.com/simonw/datasette/issues/1184", "label": "#1184"}, {"href": "https://github.com/simonw/datasette/issues/1185", "label": "#1185"}, {"href": "https://github.com/simonw/datasette/issues/1198", "label": "#1198"}, {"href": "https://github.com/simonw/datasette/issues/1194", "label": "#1194"}, {"href": "https://github.com/simonw/datasette/issues/1181", "label": "#1181"}]


id: changelog:id35
page: changelog
ref: id35
title: 0.53 (2020-12-10)
breadcrumbs: ["Changelog"]
content:
Datasette has an official project website now, at  https://datasette.io/ . This release mainly updates the documentation to reflect the new site. 
             
                 
                     New  ?column__arraynotcontains=  table filter. ( #1132 ) 
                 
                 
                     datasette serve  has a new  --create  option, which will create blank database files if they do not already exist rather than exiting with an error. ( #1135 ) 
                 
                 
                     New  ?_header=off  option for CSV export which omits the CSV header row,  documented here . ( #1133 ) 
                 
                 
                     "Powered by Datasette" link in the footer now links to  https://datasette.io/ . ( #1138 ) 
                 
                 
                     Project news no longer lives in the README - it can now be found at  https://datasette.io/news . ( #1137 )

references:
[{"href": "https://datasette.io/", "label": "https://datasette.io/"}, {"href": "https://github.com/simonw/datasette/issues/1132", "label": "#1132"}, {"href": "https://github.com/simonw/datasette/issues/1135", "label": "#1135"}, {"href": "https://github.com/simonw/datasette/issues/1133", "label": "#1133"}, {"href": "https://datasette.io/", "label": "https://datasette.io/"}, {"href": "https://github.com/simonw/datasette/issues/1138", "label": "#1138"}, {"href": "https://datasette.io/news", "label": "https://datasette.io/news"}, {"href": "https://github.com/simonw/datasette/issues/1137", "label": "#1137"}]


id: changelog:id37
page: changelog
ref: id37
title: 0.52.4 (2020-12-05)
breadcrumbs: ["Changelog"]
content:
Show  pysqlite3  version on  /-/versions , if installed. ( #1125 ) 
                 
                 
                     Errors output by Datasette (e.g. for invalid SQL queries) now go to  stderr , not  stdout . ( #1131 ) 
                 
                 
                     Fix for a startup error on windows caused by unnecessary  from os import EX_CANTCREAT  - thanks, Abdussamet Koçak.  ( #1094 )

references:
[{"href": "https://github.com/coleifer/pysqlite3", "label": "pysqlite3"}, {"href": "https://github.com/simonw/datasette/issues/1125", "label": "#1125"}, {"href": "https://github.com/simonw/datasette/issues/1131", "label": "#1131"}, {"href": "https://github.com/simonw/datasette/issues/1094", "label": "#1094"}]


id: changelog:id39
page: changelog
ref: id39
title: 0.52.2 (2020-12-02)
breadcrumbs: ["Changelog"]
content:
Generated columns from SQLite 3.31.0 or higher are now correctly displayed. ( #1116 ) 
                 
                 
                     Error message if you attempt to open a SpatiaLite database now suggests using  --load-extension=spatialite  if it detects that the extension is available in a common location. ( #1115 ) 
                 
                 
                     OPTIONS  requests against the  /database  page no longer raise a 500 error. ( #1100 ) 
                 
                 
                     Databases larger than 32MB that are published to Cloud Run can now be downloaded. ( #749 ) 
                 
                 
                     Fix for misaligned cog icon on table and database pages. Thanks, Abdussamet Koçak. ( #1121 )

references:
[{"href": "https://github.com/simonw/datasette/issues/1116", "label": "#1116"}, {"href": "https://github.com/simonw/datasette/issues/1115", "label": "#1115"}, {"href": "https://github.com/simonw/datasette/issues/1100", "label": "#1100"}, {"href": "https://github.com/simonw/datasette/issues/749", "label": "#749"}, {"href": "https://github.com/simonw/datasette/issues/1121", "label": "#1121"}]


id: changelog:id40
page: changelog
ref: id40
title: 0.52.1 (2020-11-29)
breadcrumbs: ["Changelog"]
content:
Documentation on  Testing plugins  now recommends using  datasette.client . ( #1102 ) 
                 
                 
                     Fix bug where compound foreign keys produced broken links. ( #1098 ) 
                 
                 
                     datasette --load-module=spatialite  now also checks for  /usr/local/lib/mod_spatialite.so . Thanks, Dan Peterson. ( #1114 )

references:
[{"href": "https://github.com/simonw/datasette/issues/1102", "label": "#1102"}, {"href": "https://github.com/simonw/datasette/issues/1098", "label": "#1098"}, {"href": "https://github.com/simonw/datasette/issues/1114", "label": "#1114"}]


id: changelog:id41
page: changelog
ref: id41
title: 0.52 (2020-11-28)
breadcrumbs: ["Changelog"]
content:
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 )

references:
[{"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"}]


id: changelog:id43
page: changelog
ref: id43
title: 0.51 (2020-10-31)
breadcrumbs: ["Changelog"]
references: []
content:
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.


id: changelog:new-visual-design
page: changelog
ref: new-visual-design
title: New visual design
breadcrumbs: ["Changelog", "0.51 (2020-10-31)"]
content:
Datasette is no longer white and grey with blue and purple links!  Natalie Downe  has been working on a visual refresh, the first iteration of which is included in this release. ( #1056 )

references:
[{"href": "https://twitter.com/natbat", "label": "Natalie Downe"}, {"href": "https://github.com/simonw/datasette/pull/1056", "label": "#1056"}]


id: changelog:plugins-can-now-add-links-within-datasette
page: changelog
ref: plugins-can-now-add-links-within-datasette
title: Plugins can now add links within Datasette
breadcrumbs: ["Changelog", "0.51 (2020-10-31)"]
content:
A number of existing Datasette plugins add new pages to the Datasette interface, providig tools for things like  uploading CSVs ,  editing table schemas  or  configuring full-text search . 
                 Plugins like this can now link to themselves from other parts of Datasette interface. The  menu_links(datasette, actor, request)  hook ( #1064 ) lets plugins add links to Datasette's new top-right application menu, and the  table_actions(datasette, actor, database, table, request)  hook ( #1066 ) adds links to a new "table actions" menu on the table page. 
                 The demo at  latest.datasette.io  now includes some example plugins. To see the new table actions menu first  sign into that demo as root  and then visit the  facetable  table to see the new cog icon menu at the top of the page.

references:
[{"href": "https://github.com/simonw/datasette-upload-csvs", "label": "uploading CSVs"}, {"href": "https://github.com/simonw/datasette-edit-schema", "label": "editing table schemas"}, {"href": "https://github.com/simonw/datasette-configure-fts", "label": "configuring full-text search"}, {"href": "https://github.com/simonw/datasette/issues/1064", "label": "#1064"}, {"href": "https://github.com/simonw/datasette/issues/1066", "label": "#1066"}, {"href": "https://latest.datasette.io/", "label": "latest.datasette.io"}, {"href": "https://latest.datasette.io/login-as-root", "label": "sign into that demo as root"}, {"href": "https://latest.datasette.io/fixtures/facetable", "label": "facetable"}]


id: changelog:binary-data
page: changelog
ref: binary-data
title: Binary data
breadcrumbs: ["Changelog", "0.51 (2020-10-31)"]
content:
SQLite tables can contain binary data in  BLOB  columns. Datasette now provides links for users to download this data directly from Datasette, and uses those links to make binary data available from CSV exports. See  Binary data  for more details. ( #1036  and  #1034 ).

references:
[{"href": "https://github.com/simonw/datasette/issues/1036", "label": "#1036"}, {"href": "https://github.com/simonw/datasette/issues/1034", "label": "#1034"}]


id: changelog:url-building
page: changelog
ref: url-building
title: URL building
breadcrumbs: ["Changelog", "0.51 (2020-10-31)"]
references: [{"href": "https://github.com/simonw/datasette/issues/904", "label": "#904"}]
content:
The new  datasette.urls  family of methods can be used to generate URLs to key pages within the Datasette interface, both within custom templates and Datasette plugins. See  Building URLs within plugins  for more details. ( #904 )


id: changelog:running-datasette-behind-a-proxy
page: changelog
ref: running-datasette-behind-a-proxy
title: Running Datasette behind a proxy
breadcrumbs: ["Changelog", "0.51 (2020-10-31)"]
content:
The  base_url  configuration option is designed to help run Datasette on a specific path behind a proxy - for example if you want to run an instance of Datasette at  /my-datasette/  within your existing site's URL hierarchy, proxied behind nginx or Apache. 
                 Support for this configuration option has been greatly improved ( #1023 ), and guidelines for using it are now available in a new documentation section on  Running Datasette behind a proxy . ( #1027 )

references:
[{"href": "https://github.com/simonw/datasette/issues/1023", "label": "#1023"}, {"href": "https://github.com/simonw/datasette/issues/1027", "label": "#1027"}]


id: changelog:smaller-changes
page: changelog
ref: smaller-changes
title: Smaller changes
breadcrumbs: ["Changelog", "0.51 (2020-10-31)"]
content:
Wide tables shown within Datasette now scroll horizontally ( #998 ). This is achieved using a new  <div class="table-wrapper">  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 )

references:
[{"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"}]


id: changelog:id44
page: changelog
ref: id44
title: 0.50.2 (2020-10-09)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/1011", "label": "#1011"}]
content:
Fixed another bug introduced in 0.50 where column header links on the table page were broken. ( #1011 )


id: changelog:id45
page: changelog
ref: id45
title: 0.50.1 (2020-10-09)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/1010", "label": "#1010"}]
content:
Fixed a bug introduced in 0.50 where the export as JSON/CSV links on the table, row and query pages were broken. ( #1010 )


id: changelog:id46
page: changelog
ref: id46
title: 0.50 (2020-10-09)
breadcrumbs: ["Changelog"]
content:
The key new feature in this release is the  column actions  menu on the table page ( #891 ). This can be used to sort a column in ascending or descending order, facet data by that column or filter the table to just rows that have a value for that column. 
             Plugin authors can use the new  datasette.client  object to make internal HTTP requests from their plugins, allowing them to make use of Datasette's JSON API. ( #943 ) 
             New  Deploying Datasette  documentation with guides for deploying Datasette on a Linux server  using systemd  or to hosting providers  that support buildpacks . ( #514 ,  #997 ) 
             Other improvements in this release: 
             
                 
                     Publishing to Google Cloud Run  documentation now covers Google Cloud SDK options. Thanks, Geoffrey Hing. ( #995 ) 
                 
                 
                     New  datasette -o  option which opens your browser as soon as Datasette starts up. ( #970 ) 
                 
                 
                     Datasette now sets  sqlite3.enable_callback_tracebacks(True)  so that errors in custom SQL functions will display tracebacks. ( #891 ) 
                 
                 
                     Fixed two rendering bugs with column headers in portrait mobile view. ( #978 ,  #980 ) 
                 
                 
                     New  db.table_column_details(table)  introspection method for retrieving full details of the columns in a specific table, see  Database introspection . 
                 
                 
                     Fixed a routing bug with custom page wildcard templates. ( #996 ) 
                 
                 
                     datasette publish heroku  now deploys using Python 3.8.6. 
                 
                 
                     New  datasette publish heroku --tar=  option. ( #969 ) 
                 
                 
                     OPTIONS  requests against HTML pages no longer return a 500 error. ( #1001 ) 
                 
                 
                     Datasette now supports Python 3.9. 
                 
             
             See also  Datasette 0.50: The annotated release notes .

references:
[{"href": "https://github.com/simonw/datasette/issues/891", "label": "#891"}, {"href": "https://github.com/simonw/datasette/issues/943", "label": "#943"}, {"href": "https://github.com/simonw/datasette/issues/514", "label": "#514"}, {"href": "https://github.com/simonw/datasette/issues/997", "label": "#997"}, {"href": "https://github.com/simonw/datasette/pull/995", "label": "#995"}, {"href": "https://github.com/simonw/datasette/issues/970", "label": "#970"}, {"href": "https://github.com/simonw/datasette/issues/891", "label": "#891"}, {"href": "https://github.com/simonw/datasette/issues/978", "label": "#978"}, {"href": "https://github.com/simonw/datasette/issues/980", "label": "#980"}, {"href": "https://github.com/simonw/datasette/issues/996", "label": "#996"}, {"href": "https://github.com/simonw/datasette/issues/969", "label": "#969"}, {"href": "https://github.com/simonw/datasette/issues/1001", "label": "#1001"}, {"href": "https://simonwillison.net/2020/Oct/9/datasette-0-50/", "label": "Datasette 0.50: The annotated release notes"}]


id: changelog:id47
page: changelog
ref: id47
title: 0.49.1 (2020-09-15)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/967", "label": "#967"}]
content:
Fixed a bug with writable canned queries that use magic parameters but accept no non-magic arguments. ( #967 )


id: changelog:id48
page: changelog
ref: id48
title: 0.49 (2020-09-14)
breadcrumbs: ["Changelog"]
content:
See also  Datasette 0.49: The annotated release notes . 
             
                 
                     Writable canned queries now expose a JSON API, see  JSON API for writable canned queries . ( #880 ) 
                 
                 
                     New mechanism for defining page templates with custom path parameters - a template file called  pages/about/{slug}.html  will be used to render any requests to  /about/something . See  Path parameters for pages . ( #944 ) 
                 
                 
                     register_output_renderer()  render functions can now return a  Response . ( #953 ) 
                 
                 
                     New  --upgrade  option for  datasette install . ( #945 ) 
                 
                 
                     New  datasette --pdb  option. ( #962 ) 
                 
                 
                     datasette --get  exit code now reflects the internal HTTP status code. ( #947 ) 
                 
                 
                     New  raise_404()  template function for returning 404 errors. ( #964 ) 
                 
                 
                     datasette publish heroku  now deploys using Python 3.8.5 
                 
                 
                     Upgraded  CodeMirror  to 5.57.0. ( #948 ) 
                 
                 
                     Upgraded code style to Black 20.8b1. ( #958 ) 
                 
                 
                     Fixed bug where selected facets were not correctly persisted in hidden form fields on the table page. ( #963 ) 
                 
                 
                     Renamed the default error template from  500.html  to  error.html . 
                 
                 
                     Custom error pages are now documented, see  Custom error pages . ( #965 )

references:
[{"href": "https://simonwillison.net/2020/Sep/15/datasette-0-49/", "label": "Datasette 0.49: The annotated release notes"}, {"href": "https://github.com/simonw/datasette/issues/880", "label": "#880"}, {"href": "https://github.com/simonw/datasette/issues/944", "label": "#944"}, {"href": "https://github.com/simonw/datasette/issues/953", "label": "#953"}, {"href": "https://github.com/simonw/datasette/issues/945", "label": "#945"}, {"href": "https://github.com/simonw/datasette/issues/962", "label": "#962"}, {"href": "https://github.com/simonw/datasette/issues/947", "label": "#947"}, {"href": "https://github.com/simonw/datasette/issues/964", "label": "#964"}, {"href": "https://codemirror.net/", "label": "CodeMirror"}, {"href": "https://github.com/simonw/datasette/issues/948", "label": "#948"}, {"href": "https://github.com/simonw/datasette/issues/958", "label": "#958"}, {"href": "https://github.com/simonw/datasette/issues/963", "label": "#963"}, {"href": "https://github.com/simonw/datasette/issues/965", "label": "#965"}]


id: changelog:id49
page: changelog
ref: id49
title: 0.48 (2020-08-16)
breadcrumbs: ["Changelog"]
content:
Datasette documentation now lives at  docs.datasette.io . 
                 
                 
                     db.is_mutable  property is now documented and tested, see  Database introspection . 
                 
                 
                     The  extra_template_vars ,  extra_css_urls ,  extra_js_urls  and  extra_body_script  plugin hooks now all accept the same arguments. See  extra_template_vars(template, database, table, columns, view_name, request, datasette)  for details. ( #939 ) 
                 
                 
                     Those hooks now accept a new  columns  argument detailing the table columns that will be rendered on that page. ( #938 ) 
                 
                 
                     Fixed bug where plugins calling  db.execute_write_fn()  could hang Datasette if the connection failed. ( #935 ) 
                 
                 
                     Fixed bug with the  ?_nl=on  output option and binary data. ( #914 )

references:
[{"href": "https://docs.datasette.io/", "label": "docs.datasette.io"}, {"href": "https://github.com/simonw/datasette/issues/939", "label": "#939"}, {"href": "https://github.com/simonw/datasette/issues/938", "label": "#938"}, {"href": "https://github.com/simonw/datasette/issues/935", "label": "#935"}, {"href": "https://github.com/simonw/datasette/issues/914", "label": "#914"}]


id: changelog:id50
page: changelog
ref: id50
title: 0.47.3 (2020-08-15)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/934", "label": "#934"}]
content:
The  datasette --get  command-line mechanism now ensures any plugins using the  startup()  hook are correctly executed. ( #934 )


id: changelog:id51
page: changelog
ref: id51
title: 0.47.2 (2020-08-12)
content: Fixed an issue with the Docker image published to Docker Hub . ( #931 )
breadcrumbs: ["Changelog"]
references:
[{"href": "https://hub.docker.com/r/datasetteproject/datasette", "label": "published to Docker Hub"}, {"href": "https://github.com/simonw/datasette/issues/931", "label": "#931"}]


id: changelog:id52
page: changelog
ref: id52
title: 0.47.1 (2020-08-11)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/930", "label": "#930"}]
content:
Fixed a bug where the  sdist  distribution of Datasette was not correctly including the template files. ( #930 )


id: changelog:id53
page: changelog
ref: id53
title: 0.47 (2020-08-11)
breadcrumbs: ["Changelog"]
content:
Datasette now has  a GitHub discussions forum  for conversations about the project that go beyond just bug reports and issues. 
                 
                 
                     Datasette can now be installed on macOS using Homebrew! Run  brew install simonw/datasette/datasette . See  Using Homebrew . ( #335 ) 
                 
                 
                     Two new commands:  datasette install name-of-plugin  and  datasette uninstall name-of-plugin . These are equivalent to  pip install  and  pip uninstall  but automatically run in the same virtual environment as Datasette, so users don't have to figure out where that virtual environment is - useful for installations created using Homebrew or  pipx . See  Installing plugins . ( #925 ) 
                 
                 
                     A new command-line option,  datasette --get , accepts a path to a URL within the Datasette instance. It will run that request through Datasette (without starting a web server) and print out the response. See  datasette --get  for an example. ( #926 )

references:
[{"href": "https://github.com/simonw/datasette/discussions", "label": "a GitHub discussions forum"}, {"href": "https://github.com/simonw/datasette/issues/335", "label": "#335"}, {"href": "https://github.com/simonw/datasette/issues/925", "label": "#925"}, {"href": "https://github.com/simonw/datasette/issues/926", "label": "#926"}]


id: changelog:id54
page: changelog
ref: id54
title: 0.46 (2020-08-09)
breadcrumbs: ["Changelog"]
content:
This release contains a security fix related to authenticated writable canned queries. If you are using this feature you should upgrade as soon as possible. 
             
             
                 
                     Security fix:  CSRF tokens were incorrectly included in read-only canned query forms, which could allow them to be leaked to a sophisticated attacker. See  issue 918  for details. 
                 
                 
                     Datasette now supports GraphQL via the new  datasette-graphql  plugin - see  GraphQL in Datasette with the new datasette-graphql plugin . 
                 
                 
                     Principle git branch has been renamed from  master  to  main . ( #849 ) 
                 
                 
                     New debugging tool:  /-/allow-debug tool  ( demo here ) helps test allow blocks against actors, as described in  Defining permissions with "allow" blocks . ( #908 ) 
                 
                 
                     New logo for the documentation, and a new project tagline: "An open source multi-tool for exploring and publishing data". 
                 
                 
                     Whitespace in column values is now respected on display, using  white-space: pre-wrap . ( #896 ) 
                 
                 
                     New  await request.post_body()  method for accessing the raw POST body, see  Request object . ( #897 ) 
                 
                 
                     Database file downloads now include a  content-length  HTTP header, enabling download progress bars. ( #905 ) 
                 
                 
                     File downloads now also correctly set the suggested file name using a  content-disposition  HTTP header. ( #909 ) 
                 
                 
                     tests  are now excluded from the Datasette package properly - thanks, abeyerpath. ( #456 ) 
                 
                 
                     The Datasette package published to PyPI now includes  sdist  as well as  bdist_wheel . 
                 
                 
                     Better titles for canned query pages. ( #887 ) 
                 
                 
                     Now only loads Python files from a directory passed using the  --plugins-dir  option - thanks, Amjith Ramanujam. ( #890 ) 
                 
                 
                     New documentation section on  Publishing to Vercel .

references:
[{"href": "https://github.com/simonw/datasette/issues/918", "label": "issue 918"}, {"href": "https://github.com/simonw/datasette-graphql", "label": "datasette-graphql"}, {"href": "https://simonwillison.net/2020/Aug/7/datasette-graphql/", "label": "GraphQL in Datasette with the new datasette-graphql plugin"}, {"href": "https://github.com/simonw/datasette/issues/849", "label": "#849"}, {"href": "https://latest.datasette.io/-/allow-debug", "label": "demo here"}, {"href": "https://github.com/simonw/datasette/issues/908", "label": "#908"}, {"href": "https://github.com/simonw/datasette/issues/896", "label": "#896"}, {"href": "https://github.com/simonw/datasette/issues/897", "label": "#897"}, {"href": "https://github.com/simonw/datasette/issues/905", "label": "#905"}, {"href": "https://github.com/simonw/datasette/issues/909", "label": "#909"}, {"href": "https://github.com/simonw/datasette/issues/456", "label": "#456"}, {"href": "https://github.com/simonw/datasette/issues/887", "label": "#887"}, {"href": "https://github.com/simonw/datasette/pull/890", "label": "#890"}]


id: changelog:id55
page: changelog
ref: id55
title: 0.45 (2020-07-01)
breadcrumbs: ["Changelog"]
content:
See also  Datasette 0.45: The annotated release notes . 
             Magic parameters for canned queries, a log out feature, improved plugin documentation and four new plugin hooks.

references:
[{"href": "https://simonwillison.net/2020/Jul/1/datasette-045/", "label": "Datasette 0.45: The annotated release notes"}]


id: changelog:magic-parameters-for-canned-queries
page: changelog
ref: magic-parameters-for-canned-queries
title: Magic parameters for canned queries
breadcrumbs: ["Changelog", "0.45 (2020-07-01)"]
references: [{"href": "https://github.com/simonw/datasette/issues/842", "label": "#842"}]
content:
Canned queries now support  Magic parameters , which can be used to insert or select automatically generated values. For example: 
                 insert into logs
  (user_id, timestamp)
values
  (:_actor_id, :_now_datetime_utc) 
                 This inserts the currently authenticated actor ID and the current datetime. ( #842 )


id: changelog:log-out
page: changelog
ref: log-out
title: Log out
breadcrumbs: ["Changelog", "0.45 (2020-07-01)"]
references: [{"href": "https://github.com/simonw/datasette/issues/840", "label": "#840"}]
content:
The  ds_actor cookie  can be used by plugins (or by Datasette's  --root mechanism ) to authenticate users. The new  /-/logout  page provides a way to clear that cookie. 
                 A "Log out" button now shows in the global navigation provided the user is authenticated using the  ds_actor  cookie. ( #840 )


id: changelog:better-plugin-documentation
page: changelog
ref: better-plugin-documentation
title: Better plugin documentation
breadcrumbs: ["Changelog", "0.45 (2020-07-01)"]
content:
The plugin documentation has been re-arranged into four sections, including a brand new section on testing plugins. ( #687 ) 
                 
                     
                         Plugins  introduces Datasette's plugin system and describes how to install and configure plugins. 
                     
                     
                         Writing plugins  describes how to author plugins, from  one-off single file plugins to packaged plugins that can be published to PyPI. It also describes how to start a plugin using the new  datasette-plugin  cookiecutter template. 
                     
                     
                         Plugin hooks  is a full list of detailed documentation for every Datasette plugin hook. 
                     
                     
                         Testing plugins  describes how to write tests for Datasette plugins, using  pytest  and  HTTPX .

references:
[{"href": "https://github.com/simonw/datasette/issues/687", "label": "#687"}, {"href": "https://github.com/simonw/datasette-plugin", "label": "datasette-plugin"}, {"href": "https://docs.pytest.org/", "label": "pytest"}, {"href": "https://www.python-httpx.org/", "label": "HTTPX"}]


id: changelog:new-plugin-hooks
page: changelog
ref: new-plugin-hooks
title: New plugin hooks
breadcrumbs: ["Changelog", "0.45 (2020-07-01)"]
content:
register_magic_parameters(datasette)  can be used to define new types of magic canned query parameters. 
                     
                     
                         startup(datasette)  can run custom code when Datasette first starts up.  datasette-init  is a new plugin that uses this hook to create database tables and views on startup if they have not yet been created. ( #834 ) 
                     
                     
                         canned_queries(datasette, database, actor)  lets plugins provide additional canned queries beyond those defined in Datasette's metadata. See  datasette-saved-queries  for an example of this hook in action. ( #852 ) 
                     
                     
                         forbidden(datasette, request, message)  is a hook for customizing how Datasette responds to 403 forbidden errors. ( #812 )

references:
[{"href": "https://github.com/simonw/datasette-init", "label": "datasette-init"}, {"href": "https://github.com/simonw/datasette/issues/834", "label": "#834"}, {"href": "https://github.com/simonw/datasette-saved-queries", "label": "datasette-saved-queries"}, {"href": "https://github.com/simonw/datasette/issues/852", "label": "#852"}, {"href": "https://github.com/simonw/datasette/issues/812", "label": "#812"}]


id: changelog:id56
page: changelog
ref: id56
title: Smaller changes
breadcrumbs: ["Changelog", "0.45 (2020-07-01)"]
content:
Cascading view permissions - so if a user has  view-table  they can view the table page even if they do not have  view-database  or  view-instance . ( #832 ) 
                     
                     
                         CSRF protection no longer applies to  Authentication: Bearer token  requests or requests without cookies. ( #835 ) 
                     
                     
                         datasette.add_message()  now works inside plugins. ( #864 ) 
                     
                     
                         Workaround for "Too many open files" error in test runs. ( #846 ) 
                     
                     
                         Respect existing  scope["actor"]  if already set by ASGI middleware. ( #854 ) 
                     
                     
                         New process for shipping  Alpha and beta releases . ( #807 ) 
                     
                     
                         {{ csrftoken() }}  now works when plugins render a template using  datasette.render_template(..., request=request) . ( #863 ) 
                     
                     
                         Datasette now creates a single  Request object  and uses it throughout the lifetime of the current HTTP request. ( #870 )

references:
[{"href": "https://github.com/simonw/datasette/issues/832", "label": "#832"}, {"href": "https://github.com/simonw/datasette/issues/835", "label": "#835"}, {"href": "https://github.com/simonw/datasette/issues/864", "label": "#864"}, {"href": "https://github.com/simonw/datasette/issues/846", "label": "#846"}, {"href": "https://github.com/simonw/datasette/issues/854", "label": "#854"}, {"href": "https://github.com/simonw/datasette/issues/807", "label": "#807"}, {"href": "https://github.com/simonw/datasette/issues/863", "label": "#863"}, {"href": "https://github.com/simonw/datasette/issues/870", "label": "#870"}]


id: changelog:id57
page: changelog
ref: id57
title: 0.44 (2020-06-11)
breadcrumbs: ["Changelog"]
content:
See also  Datasette 0.44: The annotated release notes . 
             Authentication and permissions, writable canned queries, flash messages, new plugin hooks and more.

references:
[{"href": "https://simonwillison.net/2020/Jun/12/annotated-release-notes/", "label": "Datasette 0.44: The annotated release notes"}]


id: changelog:authentication
page: changelog
ref: authentication
title: Authentication
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
content:
Prior to this release the Datasette ecosystem has treated authentication as exclusively the realm of plugins, most notably through  datasette-auth-github . 
                 0.44 introduces  Authentication and permissions  as core Datasette concepts ( #699 ). This enables different plugins to share responsibility for authenticating requests - you might have one plugin that handles user accounts and another one that allows automated access via API keys, for example. 
                 You'll need to install plugins if you want full user accounts, but default Datasette can now authenticate a single root user with the new  --root  command-line option, which outputs a one-time use URL to  authenticate as a root actor  ( #784 ): 
                 $ datasette fixtures.db --root
http://127.0.0.1:8001/-/auth-token?token=5b632f8cd44b868df625f5a6e2185d88eea5b22237fd3cc8773f107cc4fd6477
INFO:     Started server process [14973]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8001 (Press CTRL+C to quit) 
                 Plugins can implement new ways of authenticating users using the new  actor_from_request(datasette, request)  hook.

references:
[{"href": "https://github.com/simonw/datasette-auth-github", "label": "datasette-auth-github"}, {"href": "https://github.com/simonw/datasette/issues/699", "label": "#699"}, {"href": "https://github.com/simonw/datasette/issues/784", "label": "#784"}]


id: changelog:permissions
page: changelog
ref: permissions
title: Permissions
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
references: [{"href": "https://github.com/simonw/datasette/issues/788", "label": "#788"}]
content:
Datasette also now has a built-in concept of  Permissions . The permissions system answers the following question: 
                 
                     Is this  actor  allowed to perform this  action , optionally against this particular  resource ? 
                 
                 You can use the new  "allow"  block syntax in  metadata.json  (or  metadata.yaml ) to set required permissions at the instance, database, table or canned query level. For example, to restrict access to the  fixtures.db  database to the  "root"  user: 
                 {
    "databases": {
        "fixtures": {
            "allow": {
                "id" "root"
            }
        }
    }
} 
                 See  Defining permissions with "allow" blocks  for more details. 
                 Plugins can implement their own custom permission checks using the new  permission_allowed(datasette, actor, action, resource)  hook. 
                 A new debug page at  /-/permissions  shows recent permission checks, to help administrators and plugin authors understand exactly what checks are being performed. This tool defaults to only being available to the root user, but can be exposed to other users by plugins that respond to the  permissions-debug  permission. ( #788 )


id: changelog:writable-canned-queries
page: changelog
ref: writable-canned-queries
title: Writable canned queries
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
content:
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.

references:
[{"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"}]


id: changelog:flash-messages
page: changelog
ref: flash-messages
title: Flash messages
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
content:
Writable canned queries needed a mechanism to let the user know that the query has been successfully executed. The new flash messaging system ( #790 ) allows messages to persist in signed cookies which are then displayed to the user on the next page that they visit. Plugins can use this mechanism to display their own messages, see  .add_message(request, message, type=datasette.INFO)  for details. 
                 You can try out the new messages using the  /-/messages  debug tool, for example at  https://latest.datasette.io/-/messages

references:
[{"href": "https://github.com/simonw/datasette/issues/790", "label": "#790"}, {"href": "https://latest.datasette.io/-/messages", "label": "https://latest.datasette.io/-/messages"}]


id: changelog:signed-values-and-secrets
page: changelog
ref: signed-values-and-secrets
title: Signed values and secrets
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
references: []
content:
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.


id: changelog:csrf-protection
page: changelog
ref: csrf-protection
title: CSRF protection
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
references: [{"href": "https://github.com/simonw/datasette/issues/798", "label": "#798"}]
content:
Since writable canned queries are built using POST forms, Datasette now ships with  CSRF protection  ( #798 ). This applies automatically to any POST request, which means plugins need to include a  csrftoken  in any POST forms that they render. They can do that like so: 
                 <input type="hidden" name="csrftoken" value="{{ csrftoken() }}">


id: changelog:cookie-methods
page: changelog
ref: cookie-methods
title: Cookie methods
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
references: []
content:
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.


id: changelog:register-routes-plugin-hooks
page: changelog
ref: register-routes-plugin-hooks
title: register_routes() plugin hooks
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
references: [{"href": "https://github.com/simonw/datasette/issues/819", "label": "#819"}]
content:
Plugins can now register new views and routes via the  register_routes(datasette)  plugin hook ( #819 ). View functions can be defined that accept any of the current  datasette  object, the current  request , or the ASGI  scope ,  send  and  receive  objects.


id: changelog:id58
page: changelog
ref: id58
title: Smaller changes
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
content:
New internals documentation for  Request object  and  Response class . ( #706 ) 
                     
                     
                         request.url  now respects the  force_https_urls  config setting. closes ( #781 ) 
                     
                     
                         request.args.getlist()  returns  []  if missing. Removed  request.raw_args  entirely. ( #774 ) 
                     
                     
                         New  datasette.get_database()  method. 
                     
                     
                         Added  _  prefix to many private, undocumented methods of the Datasette class. ( #576 ) 
                     
                     
                         Removed the  db.get_outbound_foreign_keys()  method which duplicated the behaviour of  db.foreign_keys_for_table() . 
                     
                     
                         New  await datasette.permission_allowed()  method. 
                     
                     
                         /-/actor  debugging endpoint for viewing the currently authenticated actor. 
                     
                     
                         New  request.cookies  property. 
                     
                     
                         /-/plugins  endpoint now shows a list of hooks implemented by each plugin, e.g.  https://latest.datasette.io/-/plugins?all=1 
                     
                     
                         request.post_vars()  method no longer discards empty values. 
                     
                     
                         New "params" canned query key for explicitly setting named parameters, see  Canned query parameters . ( #797 ) 
                     
                     
                         request.args  is now a  MultiParams  object. 
                     
                     
                         Fixed a bug with the  datasette plugins  command. ( #802 ) 
                     
                     
                         Nicer pattern for using  make_app_client()  in tests. ( #395 ) 
                     
                     
                         New  request.actor  property. 
                     
                     
                         Fixed broken CSS on nested 404 pages. ( #777 ) 
                     
                     
                         New  request.url_vars  property. ( #822 ) 
                     
                     
                         Fixed a bug with the  python tests/fixtures.py  command for outputting Datasette's testing fixtures database and plugins. ( #804 ) 
                     
                     
                         datasette publish heroku  now deploys using Python 3.8.3. 
                     
                     
                         Added a warning that the  register_facet_classes()  hook is unstable and may change in the future. ( #830 ) 
                     
                     
                         The  {"$env": "ENVIRONMENT_VARIBALE"}  mechanism (see  Secret configuration values ) now works with variables inside nested lists. ( #837 )

references:
[{"href": "https://github.com/simonw/datasette/issues/706", "label": "#706"}, {"href": "https://github.com/simonw/datasette/issues/781", "label": "#781"}, {"href": "https://github.com/simonw/datasette/issues/774", "label": "#774"}, {"href": "https://github.com/simonw/datasette/issues/576", "label": "#576"}, {"href": "https://latest.datasette.io/-/plugins?all=1", "label": "https://latest.datasette.io/-/plugins?all=1"}, {"href": "https://github.com/simonw/datasette/issues/797", "label": "#797"}, {"href": "https://github.com/simonw/datasette/issues/802", "label": "#802"}, {"href": "https://github.com/simonw/datasette/issues/395", "label": "#395"}, {"href": "https://github.com/simonw/datasette/issues/777", "label": "#777"}, {"href": "https://github.com/simonw/datasette/issues/822", "label": "#822"}, {"href": "https://github.com/simonw/datasette/issues/804", "label": "#804"}, {"href": "https://github.com/simonw/datasette/issues/830", "label": "#830"}, {"href": "https://github.com/simonw/datasette/issues/837", "label": "#837"}]


id: changelog:the-road-to-datasette-1-0
page: changelog
ref: the-road-to-datasette-1-0
title: The road to Datasette 1.0
breadcrumbs: ["Changelog", "0.44 (2020-06-11)"]
content:
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 .

references:
[{"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"}]


id: changelog:id59
page: changelog
ref: id59
title: 0.43 (2020-05-28)
breadcrumbs: ["Changelog"]
content:
The main focus of this release is a major upgrade to the  register_output_renderer(datasette)  plugin hook, which allows plugins to provide new output formats for Datasette such as  datasette-atom  and  datasette-ics . 
             
                 
                     Redesign of  register_output_renderer(datasette)  to provide more context to the render callback and support an optional  "can_render"  callback that controls if a suggested link to the output format is provided. ( #581 ,  #770 ) 
                 
                 
                     Visually distinguish float and integer columns - useful for figuring out why order-by-column might be returning unexpected results. ( #729 ) 
                 
                 
                     The  Request object , which is passed to several plugin hooks, is now documented. ( #706 ) 
                 
                 
                     New  metadata.json  option for setting a custom default page size for specific tables and views, see  Setting a custom page size . ( #751 ) 
                 
                 
                     Canned queries can now be configured with a default URL fragment hash, useful when working with plugins such as  datasette-vega , see  Additional canned query options . ( #706 ) 
                 
                 
                     Fixed a bug in  datasette publish  when running on operating systems where the  /tmp  directory lives in a different volume, using a backport of the Python 3.8  shutil.copytree()  function. ( #744 ) 
                 
                 
                     Every plugin hook is now covered by the unit tests, and a new unit test checks that each plugin hook has at least one corresponding test. ( #771 ,  #773 )

references:
[{"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/issues/581", "label": "#581"}, {"href": "https://github.com/simonw/datasette/issues/770", "label": "#770"}, {"href": "https://github.com/simonw/datasette/issues/729", "label": "#729"}, {"href": "https://github.com/simonw/datasette/issues/706", "label": "#706"}, {"href": "https://github.com/simonw/datasette/issues/751", "label": "#751"}, {"href": "https://github.com/simonw/datasette-vega", "label": "datasette-vega"}, {"href": "https://github.com/simonw/datasette/issues/706", "label": "#706"}, {"href": "https://github.com/simonw/datasette/issues/744", "label": "#744"}, {"href": "https://github.com/simonw/datasette/issues/771", "label": "#771"}, {"href": "https://github.com/simonw/datasette/issues/773", "label": "#773"}]


id: changelog:id60
page: changelog
ref: id60
title: 0.42 (2020-05-08)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/685", "label": "#685"}]
content:
A small release which provides improved internal methods for use in plugins, along with documentation. See  #685 . 
             
                 
                     Added documentation for  db.execute() , see  await db.execute(sql, ...) . 
                 
                 
                     Renamed  db.execute_against_connection_in_thread()  to  db.execute_fn()  and made it a documented method, see  await db.execute_fn(fn) . 
                 
                 
                     New  results.first()  and  results.single_value()  methods, plus documentation for the  Results  class - see  Results .


id: changelog:id61
page: changelog
ref: id61
title: 0.41 (2020-05-06)
breadcrumbs: ["Changelog"]
content:
You can now create  custom pages  within your Datasette instance using a custom template file. For example, adding a template file called  templates/pages/about.html  will result in a new page being served at  /about  on your instance. See the  custom pages documentation  for full details, including how to return custom HTTP headers, redirects and status codes. ( #648 ) 
             Configuration directory mode  ( #731 ) allows you to define a custom Datasette instance as a directory. So instead of running the following: 
             $ datasette one.db two.db \
  --metadata=metadata.json \
  --template-dir=templates/ \
  --plugins-dir=plugins \
  --static css:css 
             You can instead arrange your files in a single directory called  my-project  and run this: 
             $ datasette my-project/ 
             Also in this release: 
             
                 
                     New  NOT LIKE  table filter:  ?colname__notlike=expression . ( #750 ) 
                 
                 
                     Datasette now has a  pattern portfolio  at  /-/patterns  - e.g.  https://latest.datasette.io/-/patterns . This is a page that shows every Datasette user interface component in one place, to aid core development and people building custom CSS themes. ( #151 ) 
                 
                 
                     SQLite  PRAGMA functions  such as  pragma_table_info(tablename)  are now allowed in Datasette SQL queries. ( #761 ) 
                 
                 
                     Datasette pages now consistently return a  content-type  of  text/html; charset=utf-8" . ( #752 ) 
                 
                 
                     Datasette now handles an ASGI  raw_path  value of  None , which should allow compatibility with the  Mangum  adapter for running ASGI apps on AWS Lambda. Thanks, Colin Dellow. ( #719 ) 
                 
                 
                     Installation documentation now covers how to  Using pipx . ( #756 ) 
                 
                 
                     Improved the documentation for  Full-text search . ( #748 )

references:
[{"href": "https://github.com/simonw/datasette/issues/648", "label": "#648"}, {"href": "https://github.com/simonw/datasette/issues/731", "label": "#731"}, {"href": "https://github.com/simonw/datasette/issues/750", "label": "#750"}, {"href": "https://latest.datasette.io/-/patterns", "label": "https://latest.datasette.io/-/patterns"}, {"href": "https://github.com/simonw/datasette/issues/151", "label": "#151"}, {"href": "https://www.sqlite.org/pragma.html#pragfunc", "label": "PRAGMA functions"}, {"href": "https://github.com/simonw/datasette/issues/761", "label": "#761"}, {"href": "https://github.com/simonw/datasette/issues/752", "label": "#752"}, {"href": "https://github.com/erm/mangum", "label": "Mangum"}, {"href": "https://github.com/simonw/datasette/pull/719", "label": "#719"}, {"href": "https://github.com/simonw/datasette/issues/756", "label": "#756"}, {"href": "https://github.com/simonw/datasette/issues/748", "label": "#748"}]


id: changelog:id62
page: changelog
ref: id62
title: 0.40 (2020-04-21)
breadcrumbs: ["Changelog"]
content:
Datasette  Metadata  can now be provided as a YAML file as an optional alternative to JSON. See  Using YAML for metadata . ( #713 ) 
                 
                 
                     Removed support for  datasette publish now , which used the the now-retired Zeit Now v1 hosting platform. A new plugin,  datasette-publish-now , can be installed to publish data to Zeit ( now Vercel ) Now v2. ( #710 ) 
                 
                 
                     Fixed a bug where the  extra_template_vars(request, view_name)  plugin hook was not receiving the correct  view_name . ( #716 ) 
                 
                 
                     Variables added to the template context by the  extra_template_vars()  plugin hook are now shown in the  ?_context=1  debugging mode (see  template_debug ). ( #693 ) 
                 
                 
                     Fixed a bug where the "templates considered" HTML comment was no longer being displayed. ( #689 ) 
                 
                 
                     Fixed a  datasette publish  bug where  --plugin-secret  would over-ride plugin configuration in the provided  metadata.json  file. ( #724 ) 
                 
                 
                     Added a new CSS class for customizing the canned query page. ( #727 )

references:
[{"href": "https://github.com/simonw/datasette/issues/713", "label": "#713"}, {"href": "https://github.com/simonw/datasette-publish-now", "label": "datasette-publish-now"}, {"href": "https://vercel.com/blog/zeit-is-now-vercel", "label": "now Vercel"}, {"href": "https://github.com/simonw/datasette/issues/710", "label": "#710"}, {"href": "https://github.com/simonw/datasette/issues/716", "label": "#716"}, {"href": "https://github.com/simonw/datasette/issues/693", "label": "#693"}, {"href": "https://github.com/simonw/datasette/issues/689", "label": "#689"}, {"href": "https://github.com/simonw/datasette/issues/724", "label": "#724"}, {"href": "https://github.com/simonw/datasette/issues/727", "label": "#727"}]


id: changelog:id63
page: changelog
ref: id63
title: 0.39 (2020-03-24)
breadcrumbs: ["Changelog"]
content:
New  base_url  configuration setting for serving up the correct links while running Datasette under a different URL prefix. ( #394 ) 
                 
                 
                     New metadata settings  "sort"  and  "sort_desc"  for setting the default sort order for a table. See  Setting a default sort order . ( #702 ) 
                 
                 
                     Sort direction arrow now displays by default on the primary key. This means you only have to click once (not twice) to sort in reverse order. ( #677 ) 
                 
                 
                     New  await Request(scope, receive).post_vars()  method for accessing POST form variables. ( #700 ) 
                 
                 
                     Plugin hooks  documentation now links to example uses of each plugin. ( #709 )

references:
[{"href": "https://github.com/simonw/datasette/issues/394", "label": "#394"}, {"href": "https://github.com/simonw/datasette/issues/702", "label": "#702"}, {"href": "https://github.com/simonw/datasette/issues/677", "label": "#677"}, {"href": "https://github.com/simonw/datasette/issues/700", "label": "#700"}, {"href": "https://github.com/simonw/datasette/issues/709", "label": "#709"}]


id: changelog:id64
page: changelog
ref: id64
title: 0.38 (2020-03-08)
breadcrumbs: ["Changelog"]
content:
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 )

references:
[{"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"}]


id: changelog:id65
page: changelog
ref: id65
title: 0.37.1 (2020-03-02)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/688", "label": "#688"}]
content:
Don't attempt to count table rows to display on the index page for databases > 100MB. ( #688 ) 
                 
                 
                     Print exceptions if they occur in the write thread rather than silently swallowing them. 
                 
                 
                     Handle the possibility of  scope["path"]  being a string rather than bytes 
                 
                 
                     Better documentation for the  extra_template_vars(template, database, table, columns, view_name, request, datasette)  plugin hook.


id: changelog:id66
page: changelog
ref: id66
title: 0.37 (2020-02-25)
breadcrumbs: ["Changelog"]
content:
Plugins now have a supported mechanism for writing to a database, using the new  .execute_write()  and  .execute_write_fn()  methods.  Documentation . ( #682 ) 
                 
                 
                     Immutable databases that have had their rows counted using the  inspect  command now use the calculated count more effectively - thanks, Kevin Keogh. ( #666 ) 
                 
                 
                     --reload  no longer restarts the server if a database file is modified, unless that database was opened immutable mode with  -i . ( #494 ) 
                 
                 
                     New  ?_searchmode=raw  option turns off escaping for FTS queries in  ?_search=  allowing full use of SQLite's  FTS5 query syntax . ( #676 )

references:
[{"href": "https://github.com/simonw/datasette/issues/682", "label": "#682"}, {"href": "https://github.com/simonw/datasette/pull/666", "label": "#666"}, {"href": "https://github.com/simonw/datasette/issues/494", "label": "#494"}, {"href": "https://www.sqlite.org/fts5.html#full_text_query_syntax", "label": "FTS5 query syntax"}, {"href": "https://github.com/simonw/datasette/issues/676", "label": "#676"}]


id: changelog:id67
page: changelog
ref: id67
title: 0.36 (2020-02-21)
breadcrumbs: ["Changelog"]
content:
The  datasette  object passed to plugins now has API documentation:  Datasette class . ( #576 ) 
                 
                 
                     New methods on  datasette :  .add_database()  and  .remove_database()  -  documentation . ( #671 ) 
                 
                 
                     prepare_connection()  plugin hook now takes optional  datasette  and  database  arguments -  prepare_connection(conn, database, datasette) . ( #678 ) 
                 
                 
                     Added three new plugins and one new conversion tool to the  The Datasette Ecosystem .

references:
[{"href": "https://github.com/simonw/datasette/issues/576", "label": "#576"}, {"href": "https://github.com/simonw/datasette/issues/671", "label": "#671"}, {"href": "https://github.com/simonw/datasette/issues/678", "label": "#678"}]


id: changelog:id68
page: changelog
ref: id68
title: 0.35 (2020-02-04)
breadcrumbs: ["Changelog"]
content:
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 )

references:
[{"href": "https://jinja.palletsprojects.com/", "label": "Jinja"}, {"href": "https://github.com/simonw/datasette/pull/653", "label": "#653"}]


id: changelog:id69
page: changelog
ref: id69
title: 0.34 (2020-01-29)
breadcrumbs: ["Changelog"]
content:
_search=  queries are now correctly escaped using a new  escape_fts()  custom SQL function. This means you can now run searches for strings like  park.  without seeing errors. ( #651 ) 
                 
                 
                     Google Cloud Run  is no longer in beta, so  datasette publish cloudrun  has been updated to work even if the user has not installed the  gcloud  beta components package. Thanks, Katie McLaughlin ( #660 ) 
                 
                 
                     datasette package  now accepts a  --port  option for specifying which port the resulting Docker container should listen on. ( #661 )

references:
[{"href": "https://github.com/simonw/datasette/issues/651", "label": "#651"}, {"href": "https://cloud.google.com/run/", "label": "Google Cloud Run"}, {"href": "https://github.com/simonw/datasette/pull/660", "label": "#660"}, {"href": "https://github.com/simonw/datasette/issues/661", "label": "#661"}]


id: changelog:id70
page: changelog
ref: id70
title: 0.33 (2019-12-22)
breadcrumbs: ["Changelog"]
content:
rowid  is now included in dropdown menus for filtering tables ( #636 ) 
                 
                 
                     Columns are now only suggested for faceting if they have at least one value with more than one record ( #638 ) 
                 
                 
                     Queries with no results now display "0 results" ( #637 ) 
                 
                 
                     Improved documentation for the  --static  option ( #641 ) 
                 
                 
                     asyncio task information is now included on the  /-/threads  debug page 
                 
                 
                     Bumped Uvicorn dependency 0.11 
                 
                 
                     You can now use  --port 0  to listen on an available port 
                 
                 
                     New  template_debug  setting for debugging templates, e.g.  https://latest.datasette.io/fixtures/roadside_attractions?_context=1  ( #654 )

references:
[{"href": "https://github.com/simonw/datasette/issues/636", "label": "#636"}, {"href": "https://github.com/simonw/datasette/issues/638", "label": "#638"}, {"href": "https://github.com/simonw/datasette/issues/637", "label": "#637"}, {"href": "https://github.com/simonw/datasette/issues/641", "label": "#641"}, {"href": "https://latest.datasette.io/fixtures/roadside_attractions?_context=1", "label": "https://latest.datasette.io/fixtures/roadside_attractions?_context=1"}, {"href": "https://github.com/simonw/datasette/issues/654", "label": "#654"}]


id: changelog:id71
page: changelog
ref: id71
title: 0.32 (2019-11-14)
breadcrumbs: ["Changelog"]
content:
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 )

references:
[{"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"}]


id: changelog:id72
page: changelog
ref: id72
title: 0.31.2 (2019-11-13)
breadcrumbs: ["Changelog"]
content:
Fixed a bug where  datasette publish heroku  applications failed to start ( #633 ) 
                 
                 
                     Fix for  datasette publish  with just  --source_url  - thanks, Stanley Zheng ( #572 ) 
                 
                 
                     Deployments to Heroku now use Python 3.8.0 ( #632 )

references:
[{"href": "https://github.com/simonw/datasette/issues/633", "label": "#633"}, {"href": "https://github.com/simonw/datasette/issues/572", "label": "#572"}, {"href": "https://github.com/simonw/datasette/issues/632", "label": "#632"}]


id: changelog:id74
page: changelog
ref: id74
title: 0.31 (2019-11-11)
breadcrumbs: ["Changelog"]
content:
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.

references:
[{"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"}]


id: changelog:id75
page: changelog
ref: id75
title: 0.30.2 (2019-11-02)
breadcrumbs: ["Changelog"]
content:
/-/plugins  page now uses distribution name e.g.  datasette-cluster-map  instead of the name of the underlying Python package ( datasette_cluster_map ) ( #606 ) 
                 
                 
                     Array faceting is now only suggested for columns that contain arrays of strings ( #562 ) 
                 
                 
                     Better documentation for the  --host  argument ( #574 ) 
                 
                 
                     Don't show  None  with a broken link for the label on a nullable foreign key ( #406 )

references:
[{"href": "https://github.com/simonw/datasette/issues/606", "label": "#606"}, {"href": "https://github.com/simonw/datasette/issues/562", "label": "#562"}, {"href": "https://github.com/simonw/datasette/issues/574", "label": "#574"}, {"href": "https://github.com/simonw/datasette/issues/406", "label": "#406"}]


id: changelog:id76
page: changelog
ref: id76
title: 0.30.1 (2019-10-30)
breadcrumbs: ["Changelog"]
content:
Fixed bug where  ?_where=  parameter was not persisted in hidden form fields ( #604 ) 
                 
                 
                     Fixed bug with .JSON representation of row pages - thanks, Chris Shaw ( #603 )

references:
[{"href": "https://github.com/simonw/datasette/issues/604", "label": "#604"}, {"href": "https://github.com/simonw/datasette/issues/603", "label": "#603"}]


id: changelog:id77
page: changelog
ref: id77
title: 0.30 (2019-10-18)
breadcrumbs: ["Changelog"]
content:
Added  /-/threads  debugging page 
                 
                 
                     Allow  EXPLAIN WITH...  ( #583 ) 
                 
                 
                     Button to format SQL - thanks, Tobias Kunze ( #136 ) 
                 
                 
                     Sort databases on homepage by argument order - thanks, Tobias Kunze ( #585 ) 
                 
                 
                     Display metadata footer on custom SQL queries - thanks, Tobias Kunze ( #589 ) 
                 
                 
                     Use  --platform=managed  for  publish cloudrun  ( #587 ) 
                 
                 
                     Fixed bug returning non-ASCII characters in CSV ( #584 ) 
                 
                 
                     Fix for  /foo  v.s.  /foo-bar  bug ( #601 )

references:
[{"href": "https://github.com/simonw/datasette/issues/583", "label": "#583"}, {"href": "https://github.com/simonw/datasette/issues/136", "label": "#136"}, {"href": "https://github.com/simonw/datasette/issues/585", "label": "#585"}, {"href": "https://github.com/simonw/datasette/pull/589", "label": "#589"}, {"href": "https://github.com/simonw/datasette/issues/587", "label": "#587"}, {"href": "https://github.com/simonw/datasette/issues/584", "label": "#584"}, {"href": "https://github.com/simonw/datasette/issues/601", "label": "#601"}]


id: changelog:id78
page: changelog
ref: id78
title: 0.29.3 (2019-09-02)
breadcrumbs: ["Changelog"]
content:
Fixed implementation of CodeMirror on database page ( #560 ) 
                 
                 
                     Documentation typo fixes - thanks, Min ho Kim ( #561 ) 
                 
                 
                     Mechanism for detecting if a table has FTS enabled now works if the table name used alternative escaping mechanisms ( #570 ) - for compatibility with  a recent change to sqlite-utils .

references:
[{"href": "https://github.com/simonw/datasette/issues/560", "label": "#560"}, {"href": "https://github.com/simonw/datasette/pull/561", "label": "#561"}, {"href": "https://github.com/simonw/datasette/issues/570", "label": "#570"}, {"href": "https://github.com/simonw/sqlite-utils/pull/57", "label": "a recent change to sqlite-utils"}]


id: changelog:id79
page: changelog
ref: id79
title: 0.29.2 (2019-07-13)
breadcrumbs: ["Changelog"]
content:
Bumped  Uvicorn  to 0.8.4, fixing a bug where the query string was not included in the server logs. ( #559 ) 
                 
                 
                     Fixed bug where the navigation breadcrumbs were not displayed correctly on the page for a custom query. ( #558 ) 
                 
                 
                     Fixed bug where custom query names containing unicode characters caused errors.

references:
[{"href": "https://www.uvicorn.org/", "label": "Uvicorn"}, {"href": "https://github.com/simonw/datasette/issues/559", "label": "#559"}, {"href": "https://github.com/simonw/datasette/issues/558", "label": "#558"}]


id: changelog:id80
page: changelog
ref: id80
title: 0.29.1 (2019-07-11)
breadcrumbs: ["Changelog"]
content:
Fixed bug with static mounts using relative paths which could lead to traversal exploits ( #555 ) - thanks Abdussamet Kocak! 
                 
                 
                     Datasette can now be run as a module:  python -m datasette  ( #556 ) - thanks, Abdussamet Kocak!

references:
[{"href": "https://github.com/simonw/datasette/issues/555", "label": "#555"}, {"href": "https://github.com/simonw/datasette/issues/556", "label": "#556"}]


id: changelog:asgi
page: changelog
ref: asgi
title: ASGI
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
content:
ASGI  is the Asynchronous Server Gateway Interface standard. I've been wanting to convert Datasette into an ASGI application for over a year -  Port Datasette to ASGI #272  tracks thirteen months of intermittent development - but with Datasette 0.29 the change is finally released. This also means Datasette now runs on top of  Uvicorn  and no longer depends on  Sanic . 
                 I wrote about the significance of this change in  Porting Datasette to ASGI, and Turtles all the way down . 
                 The most exciting consequence of this change is that Datasette plugins can now take advantage of the ASGI standard.

references:
[{"href": "https://asgi.readthedocs.io/", "label": "ASGI"}, {"href": "https://github.com/simonw/datasette/issues/272", "label": "Port Datasette to ASGI #272"}, {"href": "https://www.uvicorn.org/", "label": "Uvicorn"}, {"href": "https://github.com/huge-success/sanic", "label": "Sanic"}, {"href": "https://simonwillison.net/2019/Jun/23/datasette-asgi/", "label": "Porting Datasette to ASGI, and Turtles all the way down"}]


id: changelog:new-plugin-hook-asgi-wrapper
page: changelog
ref: new-plugin-hook-asgi-wrapper
title: New plugin hook: asgi_wrapper
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
content:
The  asgi_wrapper(datasette)  plugin hook allows plugins to entirely wrap the Datasette ASGI application in their own ASGI middleware. ( #520 ) 
                 Two new plugins take advantage of this hook: 
                 
                     
                         datasette-auth-github  adds a authentication layer: users will have to sign in using their GitHub account before they can view data or interact with Datasette. You can also use it to restrict access to specific GitHub users, or to members of specified GitHub  organizations  or  teams . 
                     
                     
                         datasette-cors  allows you to configure  CORS headers  for your Datasette instance. You can use this to enable JavaScript running on a whitelisted set of domains to make  fetch()  calls to the JSON API provided by your Datasette instance.

references:
[{"href": "https://github.com/simonw/datasette/issues/520", "label": "#520"}, {"href": "https://github.com/simonw/datasette-auth-github", "label": "datasette-auth-github"}, {"href": "https://help.github.com/en/articles/about-organizations", "label": "organizations"}, {"href": "https://help.github.com/en/articles/organizing-members-into-teams", "label": "teams"}, {"href": "https://github.com/simonw/datasette-cors", "label": "datasette-cors"}, {"href": "https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS", "label": "CORS headers"}]


id: changelog:new-plugin-hook-extra-template-vars
page: changelog
ref: new-plugin-hook-extra-template-vars
title: New plugin hook: extra_template_vars
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
content:
The  extra_template_vars(template, database, table, columns, view_name, request, datasette)  plugin hook allows plugins to inject their own additional variables into the Datasette template context. This can be used in conjunction with custom templates to customize the Datasette interface.  datasette-auth-github  uses this hook to add custom HTML to the new top navigation bar (which is designed to be modified by plugins, see  #540 ).

references:
[{"href": "https://github.com/simonw/datasette-auth-github", "label": "datasette-auth-github"}, {"href": "https://github.com/simonw/datasette/issues/540", "label": "#540"}]


id: changelog:secret-plugin-configuration-options
page: changelog
ref: secret-plugin-configuration-options
title: Secret plugin configuration options
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
content:
Plugins like  datasette-auth-github  need a safe way to set secret configuration options. Since the default mechanism for configuring plugins exposes those settings in  /-/metadata  a new mechanism was needed.  Secret configuration values  describes how plugins can now specify that their settings should be read from a file or an environment variable: 
                 {
    "plugins": {
        "datasette-auth-github": {
            "client_secret": {
                "$env": "GITHUB_CLIENT_SECRET"
            }
        }
    }
} 
                 These plugin secrets can be set directly using  datasette publish . See  Custom metadata and plugins  for details. ( #538  and  #543 )

references:
[{"href": "https://github.com/simonw/datasette-auth-github", "label": "datasette-auth-github"}, {"href": "https://github.com/simonw/datasette/issues/538", "label": "#538"}, {"href": "https://github.com/simonw/datasette/issues/543", "label": "#543"}]


id: changelog:v0-29-medium-changes
page: changelog
ref: v0-29-medium-changes
title: Easier custom templates for table rows
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
references: []
content:
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 %}
    <div>
        <h2>{{ row["title"] }}</h2>
        <p>{{ row["description"] }}<lp>
        <p>Category: {{ row.display("category_id") }}</p>
    </div>
{% 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.


id: changelog:through-for-joins-through-many-to-many-tables
page: changelog
ref: through-for-joins-through-many-to-many-tables
title: ?_through= for joins through many-to-many tables
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
content:
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.

references:
[{"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"}]


id: changelog:small-changes
page: changelog
ref: small-changes
title: Small changes
breadcrumbs: ["Changelog", "0.29 (2019-07-07)"]
content:
Databases published using  datasette publish  now open in  Immutable mode . ( #469 ) 
                     
                     
                         ?col__date=  now works for columns containing spaces 
                     
                     
                         Automatic label detection (for deciding which column to show when linking to a foreign key) has been improved. ( #485 ) 
                     
                     
                         Fixed bug where pagination broke when combined with an expanded foreign key. ( #489 ) 
                     
                     
                         Contributors can now run  pip install -e .[docs]  to get all of the dependencies needed to build the documentation, including  cd docs && make livehtml  support. 
                     
                     
                         Datasette's dependencies are now all specified using the  ~=  match operator. ( #532 ) 
                     
                     
                         white-space: pre-wrap  now used for table creation SQL. ( #505 ) 
                     
                 
                 Full list of commits  between 0.28 and 0.29.

references:
[{"href": "https://github.com/simonw/datasette/issues/469", "label": "#469"}, {"href": "https://github.com/simonw/datasette/issues/485", "label": "#485"}, {"href": "https://github.com/simonw/datasette/issues/489", "label": "#489"}, {"href": "https://github.com/simonw/datasette/issues/532", "label": "#532"}, {"href": "https://github.com/simonw/datasette/issues/505", "label": "#505"}, {"href": "https://github.com/simonw/datasette/compare/0.28...0.29", "label": "Full list of commits"}]


id: changelog:id82
page: changelog
ref: id82
title: 0.28 (2019-05-19)
content: A salmagundi of new features!
breadcrumbs: ["Changelog"]
references:
[{"href": "https://adamj.eu/tech/2019/01/18/a-salmagundi-of-django-alpha-announcements/", "label": "salmagundi"}]


id: changelog:v0-28-databases-that-change
page: changelog
ref: v0-28-databases-that-change
title: Supporting databases that change
breadcrumbs: ["Changelog", "0.28 (2019-05-19)"]
content:
From the beginning of the project, Datasette has been designed with read-only databases in mind. If a database is guaranteed not to change it opens up all kinds of interesting opportunities - from taking advantage of SQLite immutable mode and HTTP caching to bundling static copies of the database directly in a Docker container.  The interesting ideas in Datasette  explores this idea in detail. 
                 As my goals for the project have developed, I realized that read-only databases are no longer the right default. SQLite actually supports concurrent access very well provided only one thread attempts to write to a database at a time, and I keep encountering sensible use-cases for running Datasette on top of a database that is processing inserts and updates. 
                 So, as-of version 0.28 Datasette no longer assumes that a database file will not change. It is now safe to point Datasette at a SQLite database which is being updated by another process. 
                 Making this change was a lot of work - see tracking tickets  #418 ,  #419  and  #420 . It required new thinking around how Datasette should calculate table counts (an expensive operation against a large, changing database) and also meant reconsidering the "content hash" URLs Datasette has used in the past to optimize the performance of HTTP caches. 
                 Datasette can still run against immutable files and gains numerous performance benefits from doing so, but this is no longer the default behaviour. Take a look at the new  Performance and caching  documentation section for details on how to make the most of Datasette against data that you know will be staying read-only and immutable.

references:
[{"href": "https://simonwillison.net/2018/Oct/4/datasette-ideas/", "label": "The interesting ideas in Datasette"}, {"href": "https://github.com/simonw/datasette/issues/418", "label": "#418"}, {"href": "https://github.com/simonw/datasette/issues/419", "label": "#419"}, {"href": "https://github.com/simonw/datasette/issues/420", "label": "#420"}]


id: changelog:v0-28-faceting
page: changelog
ref: v0-28-faceting
title: Faceting improvements, and faceting plugins
breadcrumbs: ["Changelog", "0.28 (2019-05-19)"]
content:
Datasette  Facets  provide an intuitive way to quickly summarize and interact with data. Previously the only supported faceting technique was column faceting, but 0.28 introduces two powerful new capabilities: facet-by-JSON-array and the ability to define further facet types using plugins. 
                 Facet by array ( #359 ) is only available if your SQLite installation provides the  json1  extension. Datasette will automatically detect columns that contain JSON arrays of values and offer a faceting interface against those columns - useful for modelling things like tags without needing to break them out into a new table. See  Facet by JSON array  for more. 
                 The new  register_facet_classes()  plugin hook ( #445 ) can be used to register additional custom facet classes. Each facet class should provide two methods:  suggest()  which suggests facet selections that might be appropriate for a provided SQL query, and  facet_results()  which executes a facet operation and returns results. Datasette's own faceting implementations have been refactored to use the same API as these plugins.

references:
[{"href": "https://github.com/simonw/datasette/issues/359", "label": "#359"}, {"href": "https://github.com/simonw/datasette/pull/445", "label": "#445"}]


id: changelog:v0-28-publish-cloudrun
page: changelog
ref: v0-28-publish-cloudrun
title: datasette publish cloudrun
breadcrumbs: ["Changelog", "0.28 (2019-05-19)"]
content:
Google Cloud Run  is a brand new serverless hosting platform from Google, which allows you to build a Docker container which will run only when HTTP traffic is received and will shut down (and hence cost you nothing) the rest of the time. It's similar to Zeit's Now v1 Docker hosting platform which sadly is  no longer accepting signups  from new users. 
                 The new  datasette publish cloudrun  command was contributed by Romain Primet ( #434 ) and publishes selected databases to a new Datasette instance running on Google Cloud Run. 
                 See  Publishing to Google Cloud Run  for full documentation.

references:
[{"href": "https://cloud.google.com/run/", "label": "Google Cloud Run"}, {"href": "https://hyperion.alpha.spectrum.chat/zeit/now/cannot-create-now-v1-deployments~d206a0d4-5835-4af5-bb5c-a17f0171fb25?m=MTU0Njk2NzgwODM3OA==", "label": "no longer accepting signups"}, {"href": "https://github.com/simonw/datasette/pull/434", "label": "#434"}]


id: changelog:v0-28-register-output-renderer
page: changelog
ref: v0-28-register-output-renderer
title: register_output_renderer plugins
breadcrumbs: ["Changelog", "0.28 (2019-05-19)"]
content:
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.

references:
[{"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"}]


id: changelog:v0-28-medium-changes
page: changelog
ref: v0-28-medium-changes
title: Medium changes
breadcrumbs: ["Changelog", "0.28 (2019-05-19)"]
content:
Datasette now conforms to the  Black coding style  ( #449 ) - and has a unit test to enforce this in the future 
                     
                     
                         
                             
                                 New  Special table arguments : 
                                 
                                     
                                         
                                             ?columnname__in=value1,value2,value3  filter for executing SQL IN queries against a table, see  Table arguments  ( #433 ) 
                                         
                                         
                                             ?columnname__date=yyyy-mm-dd  filter which returns rows where the spoecified datetime column falls on the specified date ( 583b22a ) 
                                         
                                         
                                             ?tags__arraycontains=tag  filter which acts against a JSON array contained in a column ( 78e45ea ) 
                                         
                                         
                                             ?_where=sql-fragment  filter for the table view  ( #429 ) 
                                         
                                         
                                             ?_fts_table=mytable  and  ?_fts_pk=mycolumn  query string options can be used to specify which FTS table to use for a search query - see  Configuring full-text search for a table or view  ( #428 ) 
                                         
                                     
                                 
                             
                         
                     
                     
                         You can now pass the same table filter multiple times - for example,  ?content__not=world&content__not=hello  will return all rows where the content column is neither  hello  or  world  ( #288 ) 
                     
                     
                         You can now specify  about  and  about_url  metadata (in addition to  source  and  license ) linking to further information about a project - see  Source, license and about 
                     
                     
                         New  ?_trace=1  parameter now adds debug information showing every SQL query that was executed while constructing the page ( #435 ) 
                     
                     
                         datasette inspect  now just calculates table counts, and does not introspect other database metadata ( #462 ) 
                     
                     
                         Removed  /-/inspect  page entirely - this will be replaced by something similar in the future, see  #465 
                     
                     
                         Datasette can now run against an in-memory SQLite database. You can do this by starting it without passing any files or by using the new  --memory  option to  datasette serve . This can be useful for experimenting with SQLite queries that do not access any data, such as  SELECT 1+1  or  SELECT sqlite_version() .

references:
[{"href": "https://github.com/python/black", "label": "Black coding style"}, {"href": "https://github.com/simonw/datasette/pull/449", "label": "#449"}, {"href": "https://github.com/simonw/datasette/issues/433", "label": "#433"}, {"href": "https://github.com/simonw/datasette/commit/583b22aa28e26c318de0189312350ab2688c90b1", "label": "583b22a"}, {"href": "https://github.com/simonw/datasette/commit/78e45ead4d771007c57b307edf8fc920101f8733", "label": "78e45ea"}, {"href": "https://github.com/simonw/datasette/issues/429", "label": "#429"}, {"href": "https://github.com/simonw/datasette/issues/428", "label": "#428"}, {"href": "https://github.com/simonw/datasette/issues/288", "label": "#288"}, {"href": "https://github.com/simonw/datasette/issues/435", "label": "#435"}, {"href": "https://github.com/simonw/datasette/issues/462", "label": "#462"}, {"href": "https://github.com/simonw/datasette/issues/465", "label": "#465"}]


id: changelog:id83
page: changelog
ref: id83
title: Small changes
breadcrumbs: ["Changelog", "0.28 (2019-05-19)"]
content:
We now show the size of the database file next to the download link ( #172 ) 
                     
                     
                         New  /-/databases  introspection page shows currently connected databases ( #470 ) 
                     
                     
                         Binary data is no longer displayed on the table and row pages ( #442  - thanks, Russ Garrett) 
                     
                     
                         New show/hide SQL links on custom query pages ( #415 ) 
                     
                     
                         The  extra_body_script  plugin hook now accepts an optional  view_name  argument ( #443  - thanks, Russ Garrett) 
                     
                     
                         Bumped Jinja2 dependency to 2.10.1 ( #426 ) 
                     
                     
                         All table filters are now documented, and documentation is enforced via unit tests ( 2c19a27 ) 
                     
                     
                         New project guideline: master should stay shippable at all times! ( 31f36e1 ) 
                     
                     
                         Fixed a bug where  sqlite_timelimit()  occasionally failed to clean up after itself ( bac4e01 ) 
                     
                     
                         We no longer load additional plugins when executing pytest ( #438 ) 
                     
                     
                         Homepage now links to database views if there are less than five tables in a database ( #373 ) 
                     
                     
                         The  --cors  option is now respected by error pages ( #453 ) 
                     
                     
                         datasette publish heroku  now uses the  --include-vcs-ignore  option, which means it works under Travis CI ( #407 ) 
                     
                     
                         datasette publish heroku  now publishes using Python 3.6.8 ( 666c374 ) 
                     
                     
                         Renamed  datasette publish now  to  datasette publish nowv1  ( #472 ) 
                     
                     
                         datasette publish nowv1  now accepts multiple  --alias  parameters ( 09ef305 ) 
                     
                     
                         Removed the  datasette skeleton  command ( #476 ) 
                     
                     
                         The  documentation on how to build the documentation  now recommends  sphinx-autobuild

references:
[{"href": "https://github.com/simonw/datasette/issues/172", "label": "#172"}, {"href": "https://github.com/simonw/datasette/issues/470", "label": "#470"}, {"href": "https://github.com/simonw/datasette/pull/442", "label": "#442"}, {"href": "https://github.com/simonw/datasette/issues/415", "label": "#415"}, {"href": "https://github.com/simonw/datasette/pull/443", "label": "#443"}, {"href": "https://github.com/simonw/datasette/pull/426", "label": "#426"}, {"href": "https://github.com/simonw/datasette/commit/2c19a27d15a913e5f3dd443f04067169a6f24634", "label": "2c19a27"}, {"href": "https://github.com/simonw/datasette/commit/31f36e1b97ccc3f4387c80698d018a69798b6228", "label": "31f36e1"}, {"href": "https://github.com/simonw/datasette/commit/bac4e01f40ae7bd19d1eab1fb9349452c18de8f5", "label": "bac4e01"}, {"href": "https://github.com/simonw/datasette/issues/438", "label": "#438"}, {"href": "https://github.com/simonw/datasette/issues/373", "label": "#373"}, {"href": "https://github.com/simonw/datasette/issues/453", "label": "#453"}, {"href": "https://github.com/simonw/datasette/pull/407", "label": "#407"}, {"href": "https://github.com/simonw/datasette/commit/666c37415a898949fae0437099d62a35b1e9c430", "label": "666c374"}, {"href": "https://github.com/simonw/datasette/issues/472", "label": "#472"}, {"href": "https://github.com/simonw/datasette/commit/09ef305c687399384fe38487c075e8669682deb4", "label": "09ef305"}, {"href": "https://github.com/simonw/datasette/issues/476", "label": "#476"}]


id: changelog:id85
page: changelog
ref: id85
title: 0.27 (2019-01-31)
breadcrumbs: ["Changelog"]
content:
New command:  datasette plugins  ( documentation ) shows you the currently installed list of plugins. 
                 
                 
                     Datasette can now output  newline-delimited JSON  using the new  ?_shape=array&_nl=on  query string option. 
                 
                 
                     Added documentation on  The Datasette Ecosystem . 
                 
                 
                     Now using Python 3.7.2 as the base for the official  Datasette Docker image .

references:
[{"href": "http://ndjson.org/", "label": "newline-delimited JSON"}, {"href": "https://hub.docker.com/r/datasetteproject/datasette/", "label": "Datasette Docker image"}]


id: changelog:id86
page: changelog
ref: id86
title: 0.26.1 (2019-01-10)
breadcrumbs: ["Changelog"]
content:
/-/versions  now includes SQLite  compile_options  ( #396 ) 
                 
                 
                     datasetteproject/datasette  Docker image now uses SQLite 3.26.0 ( #397 ) 
                 
                 
                     Cleaned up some deprecation warnings under Python 3.7

references:
[{"href": "https://github.com/simonw/datasette/issues/396", "label": "#396"}, {"href": "https://hub.docker.com/r/datasetteproject/datasette", "label": "datasetteproject/datasette"}, {"href": "https://github.com/simonw/datasette/issues/397", "label": "#397"}]


id: changelog:id87
page: changelog
ref: id87
title: 0.26 (2019-01-02)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/393", "label": "#393"}]
content:
datasette serve --reload  now restarts Datasette if a database file changes on disk. 
                 
                 
                     datasette publish now  now takes an optional  --alias mysite.now.sh  argument. This will attempt to set an alias after the deploy completes. 
                 
                 
                     Fixed a bug where the advanced CSV export form failed to include the currently selected filters ( #393 )


id: changelog:id88
page: changelog
ref: id88
title: 0.25.2 (2018-12-16)
breadcrumbs: ["Changelog"]
references: []
content:
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


id: changelog:id89
page: changelog
ref: id89
title: 0.25.1 (2018-11-04)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/366", "label": "#366"}]
content:
Documentation improvements plus a fix for publishing to Zeit Now. 
             
                 
                     datasette publish now  now uses Zeit's v1 platform, to work around the new 100MB image limit. Thanks, @slygent - closes  #366 .


id: changelog:id90
page: changelog
ref: id90
title: 0.25 (2018-09-19)
breadcrumbs: ["Changelog"]
content:
New plugin hooks, improved database view support and an easier way to use more recent versions of SQLite. 
             
                 
                     New  publish_subcommand  plugin hook. A plugin can now add additional  datasette publish  publishers in addition to the default  now  and  heroku , both of which have been refactored into default plugins.  publish_subcommand documentation . Closes  #349 
                 
                 
                     New  render_cell  plugin hook. Plugins can now customize how values are displayed in the HTML tables produced by Datasette's browsable interface.  datasette-json-html  and  datasette-render-images  are two new plugins that use this hook.  render_cell documentation . Closes  #352 
                 
                 
                     New  extra_body_script  plugin hook, enabling plugins to provide additional JavaScript that should be added to the page footer.  extra_body_script documentation . 
                 
                 
                     extra_css_urls  and  extra_js_urls  hooks now take additional optional parameters, allowing them to be more selective about which pages they apply to.  Documentation . 
                 
                 
                     You can now use the  sortable_columns metadata setting  to explicitly enable sort-by-column in the interface for database views, as well as for specific tables. 
                 
                 
                     The new  fts_table  and  fts_pk  metadata settings can now be used to  explicitly configure full-text search for a table or a view , even if that table is not directly coupled to the SQLite FTS feature in the database schema itself. 
                 
                 
                     Datasette will now use  pysqlite3  in place of the standard library  sqlite3  module if it has been installed in the current environment. This makes it much easier to run Datasette against a more recent version of SQLite, including the just-released  SQLite 3.25.0  which adds window function support. More details on how to use this in  #360 
                 
                 
                     New mechanism that allows  plugin configuration options  to be set using  metadata.json .

references:
[{"href": "https://github.com/simonw/datasette/issues/349", "label": "#349"}, {"href": "https://github.com/simonw/datasette-json-html", "label": "datasette-json-html"}, {"href": "https://github.com/simonw/datasette-render-images", "label": "datasette-render-images"}, {"href": "https://github.com/simonw/datasette/issues/352", "label": "#352"}, {"href": "https://github.com/coleifer/pysqlite3", "label": "pysqlite3"}, {"href": "https://www.sqlite.org/releaselog/3_25_0.html", "label": "SQLite 3.25.0"}, {"href": "https://github.com/simonw/datasette/issues/360", "label": "#360"}]


id: changelog:id91
page: changelog
ref: id91
title: 0.24 (2018-07-23)
breadcrumbs: ["Changelog"]
content:
A number of small new features: 
             
                 
                     datasette publish heroku  now supports  --extra-options , fixes  #334 
                 
                 
                     Custom error message if SpatiaLite is needed for specified database, closes  #331 
                 
                 
                     New config option:  truncate_cells_html  for  truncating long cell values  in HTML view - closes  #330 
                 
                 
                     Documentation for  datasette publish and datasette package , closes  #337 
                 
                 
                     Fixed compatibility with Python 3.7 
                 
                 
                     datasette publish heroku  now supports app names via the  -n  option, which can also be used to overwrite an existing application [Russ Garrett] 
                 
                 
                     Title and description metadata can now be set for  canned SQL queries , closes  #342 
                 
                 
                     New  force_https_on  config option, fixes  https://  API URLs when deploying to Zeit Now - closes  #333 
                 
                 
                     ?_json_infinity=1  query string argument for handling Infinity/-Infinity values in JSON, closes  #332 
                 
                 
                     URLs displayed in the results of custom SQL queries are now URLified, closes  #298

references:
[{"href": "https://github.com/simonw/datasette/issues/334", "label": "#334"}, {"href": "https://github.com/simonw/datasette/issues/331", "label": "#331"}, {"href": "https://github.com/simonw/datasette/issues/330", "label": "#330"}, {"href": "https://github.com/simonw/datasette/issues/337", "label": "#337"}, {"href": "https://github.com/simonw/datasette/issues/342", "label": "#342"}, {"href": "https://github.com/simonw/datasette/issues/333", "label": "#333"}, {"href": "https://github.com/simonw/datasette/issues/332", "label": "#332"}, {"href": "https://github.com/simonw/datasette/issues/298", "label": "#298"}]


id: changelog:id100
page: changelog
ref: id100
title: 0.23.2 (2018-07-07)
breadcrumbs: ["Changelog"]
content:
Minor bugfix and documentation release. 
             
                 
                     CSV export now respects  --cors , fixes  #326 
                 
                 
                     Installation instructions , including docker image - closes  #328 
                 
                 
                     Fix for row pages for tables with / in, closes  #325

references:
[{"href": "https://github.com/simonw/datasette/issues/326", "label": "#326"}, {"href": "https://github.com/simonw/datasette/issues/328", "label": "#328"}, {"href": "https://github.com/simonw/datasette/issues/325", "label": "#325"}]


id: changelog:id104
page: changelog
ref: id104
title: 0.23.1 (2018-06-21)
breadcrumbs: ["Changelog"]
content:
Minor bugfix release. 
             
                 
                     Correctly display empty strings in HTML table, closes  #314 
                 
                 
                     Allow "." in database filenames, closes  #302 
                 
                 
                     404s ending in slash redirect to remove that slash, closes  #309 
                 
                 
                     Fixed incorrect display of compound primary keys with foreign key
                        references. Closes  #319 
                 
                 
                     Docs + example of canned SQL query using || concatenation. Closes  #321 
                 
                 
                     Correctly display facets with value of 0 - closes  #318 
                 
                 
                     Default 'expand labels' to checked in CSV advanced export

references:
[{"href": "https://github.com/simonw/datasette/issues/314", "label": "#314"}, {"href": "https://github.com/simonw/datasette/issues/302", "label": "#302"}, {"href": "https://github.com/simonw/datasette/issues/309", "label": "#309"}, {"href": "https://github.com/simonw/datasette/issues/319", "label": "#319"}, {"href": "https://github.com/simonw/datasette/issues/321", "label": "#321"}, {"href": "https://github.com/simonw/datasette/issues/318", "label": "#318"}]


id: changelog:id111
page: changelog
ref: id111
title: 0.23 (2018-06-18)
breadcrumbs: ["Changelog"]
content:
This release features CSV export, improved options for foreign key expansions,
                new configuration settings and improved support for SpatiaLite. 
             See  datasette/compare/0.22.1...0.23  for a full list of
                commits added since the last release.

references:
[{"href": "https://github.com/simonw/datasette/compare/0.22.1...0.23", "label": "datasette/compare/0.22.1...0.23"}]


id: changelog:csv-export
page: changelog
ref: csv-export
title: CSV export
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
content:
Any Datasette table, view or custom SQL query can now be exported as CSV. 
                 
                 Check out the  CSV export documentation  for more details, or
                    try the feature out on
                     https://fivethirtyeight.datasettes.com/fivethirtyeight/bechdel%2Fmovies 
                 If your table has more than  max_returned_rows  (default 1,000)
                    Datasette provides the option to  stream all rows . This option takes advantage
                    of async Python and Datasette's efficient  pagination  to
                    iterate through the entire matching result set and stream it back as a
                    downloadable CSV file.

references:
[{"href": "https://fivethirtyeight.datasettes.com/fivethirtyeight/bechdel%2Fmovies", "label": "https://fivethirtyeight.datasettes.com/fivethirtyeight/bechdel%2Fmovies"}]


id: changelog:foreign-key-expansions
page: changelog
ref: foreign-key-expansions
title: Foreign key expansions
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
references: []
content:
When Datasette detects a foreign key reference it attempts to resolve a label
                    for that reference (automatically or using the  Specifying the label column for a table  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.


id: changelog:new-configuration-settings
page: changelog
ref: new-configuration-settings
title: New configuration settings
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
references: [{"href": "https://www.sqlite.org/pragma.html#pragma_cache_size", "label": "per-connection cache"}]
content:
Datasette's  Settings  now also supports boolean settings. A number of new
                    configuration options have been added: 
                 
                     
                         num_sql_threads  - the number of threads used to execute SQLite queries. Defaults to 3. 
                     
                     
                         allow_facet  - enable or disable custom  Facets  using the  _facet=  parameter. Defaults to on. 
                     
                     
                         suggest_facets  - should Datasette suggest facets? Defaults to on. 
                     
                     
                         allow_download  - should users be allowed to download the entire SQLite database? Defaults to on. 
                     
                     
                         allow_sql  - should users be allowed to execute custom SQL queries? Defaults to on. 
                     
                     
                         default_cache_ttl  - Default HTTP caching max-age header in seconds. Defaults to 365 days - caching can be disabled entirely by settings this to 0. 
                     
                     
                         cache_size_kb  - Set the amount of memory SQLite uses for its  per-connection cache , in KB. 
                     
                     
                         allow_csv_stream  - allow users to stream entire result sets as a single CSV file. Defaults to on. 
                     
                     
                         max_csv_mb  - maximum size of a returned CSV file in MB. Defaults to 100MB, set to 0 to disable this limit.


id: changelog:control-http-caching-with-ttl
page: changelog
ref: control-http-caching-with-ttl
title: Control HTTP caching with ?_ttl=
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
content:
You can now customize the HTTP max-age header that is sent on a per-URL basis, using the new  ?_ttl=  query string parameter. 
                 You can set this to any value in seconds, or you can set it to 0 to disable HTTP caching entirely. 
                 Consider for example this query which returns a randomly selected member of the Avengers: 
                 select * from [avengers/avengers] order by random() limit 1 
                 If you hit the following page repeatedly you will get the same result, due to HTTP caching: 
                 /fivethirtyeight?sql=select+*+from+%5Bavengers%2Favengers%5D+order+by+random%28%29+limit+1 
                 By adding  ?_ttl=0  to the zero you can ensure the page will not be cached and get back a different super hero every time: 
                 /fivethirtyeight?sql=select+*+from+%5Bavengers%2Favengers%5D+order+by+random%28%29+limit+1&_ttl=0

references:
[{"href": "https://fivethirtyeight.datasettes.com/fivethirtyeight?sql=select+*+from+%5Bavengers%2Favengers%5D+order+by+random%28%29+limit+1", "label": "/fivethirtyeight?sql=select+*+from+%5Bavengers%2Favengers%5D+order+by+random%28%29+limit+1"}, {"href": "https://fivethirtyeight.datasettes.com/fivethirtyeight?sql=select+*+from+%5Bavengers%2Favengers%5D+order+by+random%28%29+limit+1&_ttl=0", "label": "/fivethirtyeight?sql=select+*+from+%5Bavengers%2Favengers%5D+order+by+random%28%29+limit+1&_ttl=0"}]


id: changelog:improved-support-for-spatialite
page: changelog
ref: improved-support-for-spatialite
title: Improved support for SpatiaLite
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
content:
The  SpatiaLite module 
                    for SQLite adds robust geospatial features to the database. 
                 Getting SpatiaLite working can be tricky, especially if you want to use the most
                    recent alpha version (with support for K-nearest neighbor). 
                 Datasette now includes  extensive documentation on SpatiaLite , and thanks to  Ravi Kotecha  our GitHub
                    repo includes a  Dockerfile  that can build
                    the latest SpatiaLite and configure it for use with Datasette. 
                 The  datasette publish  and  datasette package  commands now accept a new
                     --spatialite  argument which causes them to install and configure SpatiaLite
                    as part of the container they deploy.

references:
[{"href": "https://www.gaia-gis.it/fossil/libspatialite/index", "label": "SpatiaLite module"}, {"href": "https://github.com/r4vi", "label": "Ravi Kotecha"}, {"href": "https://github.com/simonw/datasette/blob/master/Dockerfile", "label": "Dockerfile"}]


id: changelog:latest-datasette-io
page: changelog
ref: latest-datasette-io
title: latest.datasette.io
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
content:
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.

references:
[{"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"}]


id: changelog:miscellaneous
page: changelog
ref: miscellaneous
title: Miscellaneous
breadcrumbs: ["Changelog", "0.23 (2018-06-18)"]
content:
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 .

references:
[{"href": "https://latest.datasette.io/fixtures.json?sql=select+neighborhood+from+facetable+order+by+pk+limit+101&_shape=arrayfirst", "label": "example"}]


id: changelog:id112
page: changelog
ref: id112
title: 0.22.1 (2018-05-23)
breadcrumbs: ["Changelog"]
content:
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]

references:
[{"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"}]


id: changelog:id115
page: changelog
ref: id115
title: 0.22 (2018-05-20)
breadcrumbs: ["Changelog"]
content:
The big new feature in this release is  Facets . Datasette can now apply faceted browse to any column in any table. It will also suggest possible facets. See the  Datasette Facets  announcement post for more details. 
             In addition to the work on facets: 
             
                 
                     Added  docs for introspection endpoints 
                 
                 
                     New  --config  option, added  --help-config , closes  #274 
                     Removed the  --page_size=  argument to  datasette serve  in favour of: 
                     datasette serve --config default_page_size:50 mydb.db 
                     Added new help section: 
                     $ datasette --help-config
Config options:
  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)
  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) 
                 
                 
                     Only apply responsive table styles to  .rows-and-column 
                     Otherwise they interfere with tables in the description, e.g. on
                         https://fivethirtyeight.datasettes.com/fivethirtyeight/nba-elo%2Fnbaallelo 
                 
                 
                     Refactored views into new  views/  modules, refs  #256 
                 
                 
                     Documentation for SQLite full-text search  support, closes  #253 
                 
                 
                     /-/versions  now includes SQLite  fts_versions , closes  #252

references:
[{"href": "https://simonwillison.net/2018/May/20/datasette-facets/", "label": "Datasette Facets"}, {"href": "https://docs.datasette.io/en/stable/introspection.html", "label": "docs for introspection endpoints"}, {"href": "https://github.com/simonw/datasette/issues/274", "label": "#274"}, {"href": "https://fivethirtyeight.datasettes.com/fivethirtyeight/nba-elo%2Fnbaallelo", "label": "https://fivethirtyeight.datasettes.com/fivethirtyeight/nba-elo%2Fnbaallelo"}, {"href": "https://github.com/simonw/datasette/issues/256", "label": "#256"}, {"href": "https://docs.datasette.io/en/stable/full_text_search.html", "label": "Documentation for SQLite full-text search"}, {"href": "https://github.com/simonw/datasette/issues/253", "label": "#253"}, {"href": "https://github.com/simonw/datasette/issues/252", "label": "#252"}]


id: changelog:id120
page: changelog
ref: id120
title: 0.21 (2018-05-05)
breadcrumbs: ["Changelog"]
content:
New JSON  _shape=  options, the ability to set table  _size=  and a mechanism for searching within specific columns. 
             
                 
                     Default tests to using a longer timelimit 
                     Every now and then a test will fail in Travis CI on Python 3.5 because it hit
                        the default 20ms SQL time limit. 
                     Test fixtures now default to a 200ms time limit, and we only use the 20ms time
                        limit for the specific test that tests query interruption. This should make
                        our tests on Python 3.5 in Travis much more stable. 
                 
                 
                     Support  _search_COLUMN=text  searches, closes  #237 
                 
                 
                     Show version on  /-/plugins  page, closes  #248 
                 
                 
                     ?_size=max  option, closes  #249 
                 
                 
                     Added  /-/versions  and  /-/versions.json , closes  #244 
                     Sample output: 
                     {
  "python": {
    "version": "3.6.3",
    "full": "3.6.3 (default, Oct  4 2017, 06:09:38) \n[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)]"
  },
  "datasette": {
    "version": "0.20"
  },
  "sqlite": {
    "version": "3.23.1",
    "extensions": {
      "json1": null,
      "spatialite": "4.3.0a"
    }
  }
} 
                 
                 
                     Renamed  ?_sql_time_limit_ms=  to  ?_timelimit , closes  #242 
                 
                 
                     New  ?_shape=array  option + tweaks to  _shape , closes  #245 
                     
                         
                             Default is now  ?_shape=arrays  (renamed from  lists ) 
                         
                         
                             New  ?_shape=array  returns an array of objects as the root object 
                         
                         
                             Changed  ?_shape=object  to return the object as the root 
                         
                         
                             Updated docs 
                         
                     
                 
                 
                     FTS tables now detected by  inspect() , closes  #240 
                 
                 
                     New  ?_size=XXX  query string parameter for table view, closes  #229 
                     Also added documentation for all of the  _special  arguments. 
                     Plus deleted some duplicate logic implementing  _group_count . 
                 
                 
                     If  max_returned_rows==page_size , increment  max_returned_rows  - fixes  #230 
                 
                 
                     New  hidden: True  option for table metadata, closes  #239 
                 
                 
                     Hide  idx_*  tables if spatialite detected, closes  #228 
                 
                 
                     Added  class=rows-and-columns  to custom query results table 
                 
                 
                     Added CSS class  rows-and-columns  to main table 
                 
                 
                     label_column  option in  metadata.json  - closes  #234

references:
[{"href": "https://github.com/simonw/datasette/issues/237", "label": "#237"}, {"href": "https://github.com/simonw/datasette/issues/248", "label": "#248"}, {"href": "https://github.com/simonw/datasette/issues/249", "label": "#249"}, {"href": "https://github.com/simonw/datasette/issues/244", "label": "#244"}, {"href": "https://github.com/simonw/datasette/issues/242", "label": "#242"}, {"href": "https://github.com/simonw/datasette/issues/245", "label": "#245"}, {"href": "https://github.com/simonw/datasette/issues/240", "label": "#240"}, {"href": "https://github.com/simonw/datasette/issues/229", "label": "#229"}, {"href": "https://github.com/simonw/datasette/issues/230", "label": "#230"}, {"href": "https://github.com/simonw/datasette/issues/239", "label": "#239"}, {"href": "https://github.com/simonw/datasette/issues/228", "label": "#228"}, {"href": "https://github.com/simonw/datasette/issues/234", "label": "#234"}]


id: changelog:id133
page: changelog
ref: id133
title: 0.20 (2018-04-20)
breadcrumbs: ["Changelog"]
content:
Mostly new work on the  Plugins  mechanism: plugins can now bundle static assets and custom templates, and  datasette publish  has a new  --install=name-of-plugin  option. 
             
                 
                     Add col-X classes to HTML table on custom query page 
                 
                 
                     Fixed out-dated template in documentation 
                 
                 
                     Plugins can now bundle custom templates,  #224 
                 
                 
                     Added /-/metadata /-/plugins /-/inspect,  #225 
                 
                 
                     Documentation for --install option, refs  #223 
                 
                 
                     Datasette publish/package --install option,  #223 
                 
                 
                     Fix for plugins in Python 3.5,  #222 
                 
                 
                     New plugin hooks: extra_css_urls() and extra_js_urls(),  #214 
                 
                 
                     /-/static-plugins/PLUGIN_NAME/ now serves static/ from plugins 
                 
                 
                     <th> now gets class="col-X" - plus added col-X documentation 
                 
                 
                     Use to_css_class for table cell column classes 
                     This ensures that columns with spaces in the name will still
                        generate usable CSS class names. Refs  #209 
                 
                 
                     Add column name classes to <td>s, make PK bold [Russ Garrett] 
                 
                 
                     Don't duplicate simple primary keys in the link column [Russ Garrett] 
                     When there's a simple (single-column) primary key, it looks weird to
                        duplicate it in the link column. 
                     This change removes the second PK column and treats the link column as
                        if it were the PK column from a header/sorting perspective. 
                 
                 
                     Correct escaping for HTML display of row links [Russ Garrett] 
                 
                 
                     Longer time limit for test_paginate_compound_keys 
                     It was failing intermittently in Travis - see  #209 
                 
                 
                     Use application/octet-stream for downloadable databases 
                 
                 
                     Updated PyPI classifiers 
                 
                 
                     Updated PyPI link to pypi.org

references:
[{"href": "https://github.com/simonw/datasette/issues/224", "label": "#224"}, {"href": "https://github.com/simonw/datasette/issues/225", "label": "#225"}, {"href": "https://github.com/simonw/datasette/issues/223", "label": "#223"}, {"href": "https://github.com/simonw/datasette/issues/223", "label": "#223"}, {"href": "https://github.com/simonw/datasette/issues/222", "label": "#222"}, {"href": "https://github.com/simonw/datasette/issues/214", "label": "#214"}, {"href": "https://github.com/simonw/datasette/issues/209", "label": "#209"}, {"href": "https://github.com/simonw/datasette/issues/209", "label": "#209"}]


id: changelog:id142
page: changelog
ref: id142
title: 0.19 (2018-04-16)
breadcrumbs: ["Changelog"]
content:
This is the first preview of the new Datasette plugins mechanism. Only two
                plugin hooks are available so far - for custom SQL functions and custom template
                filters. There's plenty more to come - read  the documentation  and get involved in
                 the tracking ticket  if you
                have feedback on the direction so far. 
             
                 
                     Fix for  _sort_desc=sortable_with_nulls  test, refs  #216 
                 
                 
                     Fixed  #216  - paginate correctly when sorting by nullable column 
                 
                 
                     Initial documentation for plugins, closes  #213 
                     https://docs.datasette.io/en/stable/plugins.html 
                 
                 
                     New  --plugins-dir=plugins/  option ( #212 ) 
                     New option causing Datasette to load and evaluate all of the Python files in
                        the specified directory and register any plugins that are defined in those
                        files. 
                     This new option is available for the following commands: 
                     datasette serve mydb.db --plugins-dir=plugins/
datasette publish now/heroku mydb.db --plugins-dir=plugins/
datasette package mydb.db --plugins-dir=plugins/ 
                 
                 
                     Start of the plugin system, based on pluggy ( #210 ) 
                     Uses  https://pluggy.readthedocs.io/  originally created for the py.test project 
                     We're starting with two plugin hooks: 
                     prepare_connection(conn) 
                     This is called when a new SQLite connection is created. It can be used to register custom SQL functions. 
                     prepare_jinja2_environment(env) 
                     This is called with the Jinja2 environment. It can be used to register custom template tags and filters. 
                     An example plugin which uses these two hooks can be found at  https://github.com/simonw/datasette-plugin-demos  or installed using  pip install datasette-plugin-demos 
                     Refs  #14 
                 
                 
                     Return HTTP 405 on InvalidUsage rather than 500. [Russ Garrett] 
                     This also stops it filling up the logs. This happens for HEAD requests
                        at the moment - which perhaps should be handled better, but that's a
                        different issue.

references:
[{"href": "https://docs.datasette.io/en/stable/plugins.html", "label": "the documentation"}, {"href": "https://github.com/simonw/datasette/issues/14", "label": "the tracking ticket"}, {"href": "https://github.com/simonw/datasette/issues/216", "label": "#216"}, {"href": "https://github.com/simonw/datasette/issues/216", "label": "#216"}, {"href": "https://github.com/simonw/datasette/issues/213", "label": "#213"}, {"href": "https://docs.datasette.io/en/stable/plugins.html", "label": "https://docs.datasette.io/en/stable/plugins.html"}, {"href": "https://github.com/simonw/datasette/issues/212", "label": "#212"}, {"href": "https://github.com/simonw/datasette/issues/14", "label": "#210"}, {"href": "https://pluggy.readthedocs.io/", "label": "https://pluggy.readthedocs.io/"}, {"href": "https://github.com/simonw/datasette-plugin-demos", "label": "https://github.com/simonw/datasette-plugin-demos"}, {"href": "https://github.com/simonw/datasette/issues/14", "label": "#14"}]


id: changelog:id149
page: changelog
ref: id149
title: 0.18 (2018-04-14)
breadcrumbs: ["Changelog"]
content:
This release introduces  support for units ,
                contributed by Russ Garrett ( #203 ).
                You can now optionally specify the units for specific columns using  metadata.json .
                Once specified, units will be displayed in the HTML view of your table. They also become
                available for use in filters - if a column is configured with a unit of distance, you can
                request all rows where that column is less than 50 meters or more than 20 feet for example. 
             
                 
                     Link foreign keys which don't have labels. [Russ Garrett] 
                     This renders unlabeled FKs as simple links. 
                     Also includes bonus fixes for two minor issues: 
                     
                         
                             In foreign key link hrefs the primary key was escaped using HTML
                                escaping rather than URL escaping. This broke some non-integer PKs. 
                         
                         
                             Print tracebacks to console when handling 500 errors. 
                         
                     
                 
                 
                     Fix SQLite error when loading rows with no incoming FKs. [Russ
                        Garrett] 
                     This fixes an error caused by an invalid query when loading incoming FKs. 
                     The error was ignored due to async but it still got printed to the
                        console. 
                 
                 
                     Allow custom units to be registered with Pint. [Russ Garrett] 
                 
                 
                     Support units in filters. [Russ Garrett] 
                 
                 
                     Tidy up units support. [Russ Garrett] 
                     
                         
                             Add units to exported JSON 
                         
                         
                             Units key in metadata skeleton 
                         
                         
                             Docs 
                         
                     
                 
                 
                     Initial units support. [Russ Garrett] 
                     Add support for specifying units for a column in  metadata.json  and
                        rendering them on display using
                         pint

references:
[{"href": "https://docs.datasette.io/en/stable/metadata.html#specifying-units-for-a-column", "label": "support for units"}, {"href": "https://github.com/simonw/datasette/issues/203", "label": "#203"}, {"href": "https://pint.readthedocs.io/en/latest/", "label": "pint"}]


id: changelog:id152
page: changelog
ref: id152
title: 0.16 (2018-04-13)
breadcrumbs: ["Changelog"]
content:
Better mechanism for handling errors; 404s for missing table/database 
                     New error mechanism closes  #193 
                     404s for missing tables/databases closes  #184 
                 
                 
                     long_description in markdown for the new PyPI 
                 
                 
                     Hide SpatiaLite system tables. [Russ Garrett] 
                 
                 
                     Allow  explain select  /  explain query plan select   #201 
                 
                 
                     Datasette inspect now finds primary_keys  #195 
                 
                 
                     Ability to sort using form fields (for mobile portrait mode)  #199 
                     We now display sort options as a select box plus a descending checkbox, which
                        means you can apply sort orders even in portrait mode on a mobile phone where
                        the column headers are hidden.

references:
[{"href": "https://github.com/simonw/datasette/issues/193", "label": "#193"}, {"href": "https://github.com/simonw/datasette/issues/184", "label": "#184"}, {"href": "https://github.com/simonw/datasette/issues/201", "label": "#201"}, {"href": "https://github.com/simonw/datasette/issues/195", "label": "#195"}, {"href": "https://github.com/simonw/datasette/issues/199", "label": "#199"}]


id: changelog:id158
page: changelog
ref: id158
title: 0.15 (2018-04-09)
breadcrumbs: ["Changelog"]
content:
The biggest new feature in this release is the ability to sort by column. On the
                table page the column headers can now be clicked to apply sort (or descending
                sort), or you can specify  ?_sort=column  or  ?_sort_desc=column  directly
                in the URL. 
             
                 
                     table_rows  =>  table_rows_count ,  filtered_table_rows  =>
                         filtered_table_rows_count 
                     Renamed properties. Closes  #194 
                 
                 
                     New  sortable_columns  option in  metadata.json  to control sort options. 
                     You can now explicitly set which columns in a table can be used for sorting
                        using the  _sort  and  _sort_desc  arguments using  metadata.json : 
                     {
    "databases": {
        "database1": {
            "tables": {
                "example_table": {
                    "sortable_columns": [
                        "height",
                        "weight"
                    ]
                }
            }
        }
    }
} 
                     Refs  #189 
                 
                 
                     Column headers now link to sort/desc sort - refs  #189 
                 
                 
                     _sort  and  _sort_desc  parameters for table views 
                     Allows for paginated sorted results based on a specified column. 
                     Refs  #189 
                 
                 
                     Total row count now correct even if  _next  applied 
                 
                 
                     Use .custom_sql() for _group_count implementation (refs  #150 ) 
                 
                 
                     Make HTML title more readable in query template ( #180 ) [Ryan Pitts] 
                 
                 
                     New  ?_shape=objects/object/lists  param for JSON API ( #192 ) 
                     New  _shape=  parameter replacing old  .jsono  extension 
                     Now instead of this: 
                     /database/table.jsono 
                     We use the  _shape  parameter like this: 
                     /database/table.json?_shape=objects 
                     Also introduced a new  _shape  called  object  which looks like this: 
                     /database/table.json?_shape=object 
                     Returning an object for the rows key: 
                     ...
"rows": {
    "pk1": {
        ...
    },
    "pk2": {
        ...
    }
} 
                     Refs  #122 
                 
                 
                     Utility for writing test database fixtures to a .db file 
                     python tests/fixtures.py /tmp/hello.db 
                     This is useful for making a SQLite database of the test fixtures for
                        interactive exploration. 
                 
                 
                     Compound primary key  _next=  now plays well with extra filters 
                     Closes  #190 
                 
                 
                     Fixed bug with keyset pagination over compound primary keys 
                     Refs  #190 
                 
                 
                     Database/Table views inherit  source/license/source_url/license_url 
                        metadata 
                     If you set the  source_url/license_url/source/license  fields in your root
                        metadata those values will now be inherited all the way down to the database
                        and table templates. 
                     The  title/description  are NOT inherited. 
                     Also added unit tests for the HTML generated by the metadata. 
                     Refs  #185 
                 
                 
                     Add metadata, if it exists, to heroku temp dir ( #178 ) [Tony Hirst] 
                 
                 
                     Initial documentation for pagination 
                 
                 
                     Broke up test_app into test_api and test_html 
                 
                 
                     Fixed bug with .json path regular expression 
                     I had a table called  geojson  and it caused an exception because the regex
                        was matching  .json  and not  \.json 
                 
                 
                     Deploy to Heroku with Python 3.6.3

references:
[{"href": "https://github.com/simonw/datasette/issues/194", "label": "#194"}, {"href": "https://github.com/simonw/datasette/issues/189", "label": "#189"}, {"href": "https://github.com/simonw/datasette/issues/189", "label": "#189"}, {"href": "https://github.com/simonw/datasette/issues/189", "label": "#189"}, {"href": "https://github.com/simonw/datasette/issues/150", "label": "#150"}, {"href": "https://github.com/simonw/datasette/issues/180", "label": "#180"}, {"href": "https://github.com/simonw/datasette/issues/192", "label": "#192"}, {"href": "https://github.com/simonw/datasette/issues/122", "label": "#122"}, {"href": "https://github.com/simonw/datasette/issues/190", "label": "#190"}, {"href": "https://github.com/simonw/datasette/issues/190", "label": "#190"}, {"href": "https://github.com/simonw/datasette/issues/185", "label": "#185"}, {"href": "https://github.com/simonw/datasette/issues/178", "label": "#178"}]


id: changelog:id171
page: changelog
ref: id171
title: 0.14 (2017-12-09)
breadcrumbs: ["Changelog"]
content:
The theme of this release is customization: Datasette now allows every aspect
                of its presentation  to be customized 
                either using additional CSS or by providing entirely new templates. 
             Datasette's  metadata.json format 
                has also been expanded, to allow per-database and per-table metadata. A new
                 datasette skeleton  command can be used to generate a skeleton JSON file
                ready to be filled in with per-database and per-table details. 
             The  metadata.json  file can also be used to define
                 canned queries ,
                as a more powerful alternative to SQL views. 
             
                 
                     extra_css_urls / extra_js_urls  in metadata 
                     A mechanism in the  metadata.json  format for adding custom CSS and JS urls. 
                     Create a  metadata.json  file that looks like this: 
                     {
    "extra_css_urls": [
        "https://simonwillison.net/static/css/all.bf8cd891642c.css"
    ],
    "extra_js_urls": [
        "https://code.jquery.com/jquery-3.2.1.slim.min.js"
    ]
} 
                     Then start datasette like this: 
                     datasette mydb.db --metadata=metadata.json 
                     The CSS and JavaScript files will be linked in the  <head>  of every page. 
                     You can also specify a SRI (subresource integrity hash) for these assets: 
                     {
    "extra_css_urls": [
        {
            "url": "https://simonwillison.net/static/css/all.bf8cd891642c.css",
            "sri": "sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI"
        }
    ],
    "extra_js_urls": [
        {
            "url": "https://code.jquery.com/jquery-3.2.1.slim.min.js",
            "sri": "sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
        }
    ]
} 
                     Modern browsers will only execute the stylesheet or JavaScript if the SRI hash
                        matches the content served. You can generate hashes using  https://www.srihash.org/ 
                 
                 
                     Auto-link column values that look like URLs ( #153 ) 
                 
                 
                     CSS styling hooks as classes on the body ( #153 ) 
                     Every template now gets CSS classes in the body designed to support custom
                        styling. 
                     The index template (the top level page at  / ) gets this: 
                     <body class="index"> 
                     The database template ( /dbname/ ) gets this: 
                     <body class="db db-dbname"> 
                     The table template ( /dbname/tablename ) gets: 
                     <body class="table db-dbname table-tablename"> 
                     The row template ( /dbname/tablename/rowid ) gets: 
                     <body class="row db-dbname table-tablename"> 
                     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 (extracted from the unit tests): 
                     "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" 
                 
                 
                     datasette --template-dir=mytemplates/  argument 
                     You can now pass an additional argument specifying a directory to look for
                        custom templates in. 
                     Datasette will fall back on the default templates if a template is not
                        found in that directory. 
                 
                 
                     Ability to over-ride templates for individual tables/databases. 
                     It is now possible to over-ride templates on a per-database / per-row or per-
                        table basis. 
                     When you access e.g.  /mydatabase/mytable  Datasette will look for the following: 
                     - table-mydatabase-mytable.html
- table.html 
                     If you provided a  --template-dir  argument to datasette serve it will look in
                        that directory first. 
                     The lookup rules are as follows: 
                     Index page (/):
    index.html

Database page (/mydatabase):
    database-mydatabase.html
    database.html

Table page (/mydatabase/mytable):
    table-mydatabase-mytable.html
    table.html

Row page (/mydatabase/mytable/id):
    row-mydatabase-mytable.html
    row.html 
                     If a table name has spaces or other unexpected characters in it, the template
                        filename will follow the same rules as our custom  <body>  CSS classes
                        - for example, a table called "Food Trucks"
                        will attempt to load the following templates: 
                     table-mydatabase-Food-Trucks-399138.html
table.html 
                     It is possible to extend the default templates using Jinja template
                        inheritance. If you want to customize EVERY row template with some additional
                        content you can do so by creating a row.html template like this: 
                     {% extends "default:row.html" %}

{% block content %}
<h1>EXTRA HTML AT THE TOP OF THE CONTENT BLOCK</h1>
<p>This line renders the original block:</p>
{{ super() }}
{% endblock %} 
                 
                 
                     --static  option for datasette serve ( #160 ) 
                     You can now tell Datasette to serve static files from a specific location at a
                        specific mountpoint. 
                     For example: 
                     datasette serve mydb.db --static extra-css:/tmp/static/css 
                     Now if you visit this URL: 
                     http://localhost:8001/extra-css/blah.css 
                     The following file will be served: 
                     /tmp/static/css/blah.css 
                 
                 
                     Canned query support. 
                     Named canned queries can now be defined in  metadata.json  like this: 
                     {
    "databases": {
        "timezones": {
            "queries": {
                "timezone_for_point": "select tzid from timezones ..."
            }
        }
    }
} 
                     These will be shown in a new "Queries" section beneath "Views" on the database page. 
                 
                 
                     New  datasette skeleton  command for generating  metadata.json  ( #164 ) 
                 
                 
                     metadata.json  support for per-table/per-database metadata ( #165 ) 
                     Also added support for descriptions and HTML descriptions. 
                     Here's an example metadata.json file illustrating custom per-database and per-
                        table metadata: 
                     {
    "title": "Overall datasette title",
    "description_html": "This is a <em>description with HTML</em>.",
    "databases": {
        "db1": {
            "title": "First database",
            "description": "This is a string description & has no HTML",
            "license_url": "http://example.com/",
        "license": "The example license",
            "queries": {
              "canned_query": "select * from table1 limit 3;"
            },
            "tables": {
                "table1": {
                    "title": "Custom title for table1",
                    "description": "Tables can have descriptions too",
                    "source": "This has a custom source",
                    "source_url": "http://example.com/"
                }
            }
        }
    }
} 
                 
                 
                     Renamed  datasette build  command to  datasette inspect  ( #130 ) 
                 
                 
                     Upgrade to Sanic 0.7.0 ( #168 ) 
                     https://github.com/channelcat/sanic/releases/tag/0.7.0 
                 
                 
                     Package and publish commands now accept  --static  and  --template-dir 
                     Example usage: 
                     datasette package --static css:extra-css/ --static js:extra-js/ \
  sf-trees.db --template-dir templates/ --tag sf-trees --branch master 
                     This creates a local Docker image that includes copies of the templates/,
                        extra-css/ and extra-js/ directories. You can then run it like this: 
                     docker run -p 8001:8001 sf-trees 
                     For publishing to Zeit now: 
                     datasette publish now --static css:extra-css/ --static js:extra-js/ \
  sf-trees.db --template-dir templates/ --name sf-trees --branch master 
                 
                 
                     HTML comment showing which templates were considered for a page ( #171 )

references:
[{"href": "https://docs.datasette.io/en/stable/custom_templates.html", "label": "to be customized"}, {"href": "https://docs.datasette.io/en/stable/metadata.html", "label": "metadata.json format"}, {"href": "https://docs.datasette.io/en/stable/sql_queries.html#canned-queries", "label": "canned queries"}, {"href": "https://www.srihash.org/", "label": "https://www.srihash.org/"}, {"href": "https://github.com/simonw/datasette/issues/153", "label": "#153"}, {"href": "https://github.com/simonw/datasette/issues/153", "label": "#153"}, {"href": "https://github.com/simonw/datasette/issues/160", "label": "#160"}, {"href": "https://github.com/simonw/datasette/issues/164", "label": "#164"}, {"href": "https://github.com/simonw/datasette/issues/165", "label": "#165"}, {"href": "https://github.com/simonw/datasette/issues/130", "label": "#130"}, {"href": "https://github.com/simonw/datasette/issues/168", "label": "#168"}, {"href": "https://github.com/channelcat/sanic/releases/tag/0.7.0", "label": "https://github.com/channelcat/sanic/releases/tag/0.7.0"}, {"href": "https://github.com/simonw/datasette/issues/171", "label": "#171"}]


id: changelog:id180
page: changelog
ref: id180
title: 0.13 (2017-11-24)
breadcrumbs: ["Changelog"]
content:
Search now applies to current filters. 
                     Combined search into the same form as filters. 
                     Closes  #133 
                 
                 
                     Much tidier design for table view header. 
                     Closes  #147 
                 
                 
                     Added  ?column__not=blah  filter. 
                     Closes  #148 
                 
                 
                     Row page now resolves foreign keys. 
                     Closes  #132 
                 
                 
                     Further tweaks to select/input filter styling. 
                     Refs  #86  - thanks for the help, @natbat! 
                 
                 
                     Show linked foreign key in table cells. 
                 
                 
                     Added UI for editing table filters. 
                     Refs  #86 
                 
                 
                     Hide FTS-created tables on index pages. 
                     Closes  #129 
                 
                 
                     Add publish to heroku support [Jacob Kaplan-Moss] 
                     datasette publish heroku mydb.db 
                     Pull request  #104 
                 
                 
                     Initial implementation of  ?_group_count=column . 
                     URL shortcut for counting rows grouped by one or more columns. 
                     ?_group_count=column1&_group_count=column2  works as well. 
                     SQL generated looks like this: 
                     select "qSpecies", count(*) as "count"
from Street_Tree_List
group by "qSpecies"
order by "count" desc limit 100 
                     Or for two columns like this: 
                     select "qSpecies", "qSiteInfo", count(*) as "count"
from Street_Tree_List
group by "qSpecies", "qSiteInfo"
order by "count" desc limit 100 
                     Refs  #44 
                 
                 
                     Added  --build=master  option to datasette publish and package. 
                     The  datasette publish  and  datasette package  commands both now accept an
                        optional  --build  argument. If provided, this can be used to specify a branch
                        published to GitHub that should be built into the container. 
                     This makes it easier to test code that has not yet been officially released to
                        PyPI, e.g.: 
                     datasette publish now mydb.db --branch=master 
                 
                 
                     Implemented  ?_search=XXX  + UI if a FTS table is detected. 
                     Closes  #131 
                 
                 
                     Added  datasette --version  support. 
                 
                 
                     Table views now show expanded foreign key references, if possible. 
                     If a table has foreign key columns, and those foreign key tables have
                         label_columns , the TableView will now query those other tables for the
                        corresponding values and display those values as links in the corresponding
                        table cells. 
                     label_columns are currently detected by the  inspect()  function, which looks
                        for any table that has just two columns - an ID column and one other - and
                        sets the  label_column  to be that second non-ID column. 
                 
                 
                     Don't prevent tabbing to "Run SQL" button ( #117 ) [Robert Gieseke] 
                     See comment in  #115 
                 
                 
                     Add keyboard shortcut to execute SQL query ( #115 ) [Robert Gieseke] 
                 
                 
                     Allow  --load-extension  to be set via environment variable. 
                 
                 
                     Add support for  ?field__isnull=1  ( #107 ) [Ray N] 
                 
                 
                     Add spatialite, switch to debian and local build ( #114 ) [Ariel Núñez] 
                 
                 
                     Added  --load-extension  argument to datasette serve. 
                     Allows loading of SQLite extensions. Refs  #110 .

references:
[{"href": "https://github.com/simonw/datasette/issues/133", "label": "#133"}, {"href": "https://github.com/simonw/datasette/issues/147", "label": "#147"}, {"href": "https://github.com/simonw/datasette/issues/148", "label": "#148"}, {"href": "https://github.com/simonw/datasette/issues/132", "label": "#132"}, {"href": "https://github.com/simonw/datasette/issues/86", "label": "#86"}, {"href": "https://github.com/simonw/datasette/issues/86", "label": "#86"}, {"href": "https://github.com/simonw/datasette/issues/129", "label": "#129"}, {"href": "https://github.com/simonw/datasette/issues/104", "label": "#104"}, {"href": "https://github.com/simonw/datasette/issues/44", "label": "#44"}, {"href": "https://github.com/simonw/datasette/issues/131", "label": "#131"}, {"href": "https://github.com/simonw/datasette/issues/117", "label": "#117"}, {"href": "https://github.com/simonw/datasette/issues/115", "label": "#115"}, {"href": "https://github.com/simonw/datasette/issues/115", "label": "#115"}, {"href": "https://github.com/simonw/datasette/issues/107", "label": "#107"}, {"href": "https://github.com/simonw/datasette/issues/114", "label": "#114"}, {"href": "https://github.com/simonw/datasette/issues/110", "label": "#110"}]


id: changelog:id195
page: changelog
ref: id195
title: 0.12 (2017-11-16)
breadcrumbs: ["Changelog"]
content:
Added  __version__ , now displayed as tooltip in page footer ( #108 ). 
                 
                 
                     Added initial docs, including a changelog ( #99 ). 
                 
                 
                     Turned on auto-escaping in Jinja. 
                 
                 
                     Added a UI for editing named parameters ( #96 ). 
                     You can now construct a custom SQL statement using SQLite named
                        parameters (e.g.  :name ) and datasette will display form fields for
                        editing those parameters.  Here’s an example  which lets you see the
                        most popular names for dogs of different species registered through
                        various dog registration schemes in Australia. 
                 
             
             
             
                 
                     Pin to specific Jinja version. ( #100 ). 
                 
                 
                     Default to 127.0.0.1 not 0.0.0.0. ( #98 ). 
                 
                 
                     Added extra metadata options to publish and package commands. ( #92 ). 
                     You can now run these commands like so: 
                     datasette now publish mydb.db \
    --title="My Title" \
    --source="Source" \
    --source_url="http://www.example.com/" \
    --license="CC0" \
    --license_url="https://creativecommons.org/publicdomain/zero/1.0/" 
                     This will write those values into the metadata.json that is packaged with the
                        app. If you also pass  --metadata=metadata.json  that file will be updated with the extra
                        values before being written into the Docker image. 
                 
                 
                     Added production-ready Dockerfile ( #94 ) [Andrew
                        Cutler] 
                 
                 
                     New  ?_sql_time_limit_ms=10  argument to database and table page ( #95 ) 
                 
                 
                     SQL syntax highlighting with Codemirror ( #89 ) [Tom Dyson]

references:
[{"href": "https://github.com/simonw/datasette/issues/108", "label": "#108"}, {"href": "https://github.com/simonw/datasette/issues/99", "label": "#99"}, {"href": "https://github.com/simonw/datasette/issues/96", "label": "#96"}, {"href": "https://australian-dogs.now.sh/australian-dogs-3ba9628?sql=select+name%2C+count%28*%29+as+n+from+%28%0D%0A%0D%0Aselect+upper%28%22Animal+name%22%29+as+name+from+%5BAdelaide-City-Council-dog-registrations-2013%5D+where+Breed+like+%3Abreed%0D%0A%0D%0Aunion+all%0D%0A%0D%0Aselect+upper%28Animal_Name%29+as+name+from+%5BAdelaide-City-Council-dog-registrations-2014%5D+where+Breed_Description+like+%3Abreed%0D%0A%0D%0Aunion+all+%0D%0A%0D%0Aselect+upper%28Animal_Name%29+as+name+from+%5BAdelaide-City-Council-dog-registrations-2015%5D+where+Breed_Description+like+%3Abreed%0D%0A%0D%0Aunion+all%0D%0A%0D%0Aselect+upper%28%22AnimalName%22%29+as+name+from+%5BCity-of-Port-Adelaide-Enfield-Dog_Registrations_2016%5D+where+AnimalBreed+like+%3Abreed%0D%0A%0D%0Aunion+all%0D%0A%0D%0Aselect+upper%28%22Animal+Name%22%29+as+name+from+%5BMitcham-dog-registrations-2015%5D+where+Breed+like+%3Abreed%0D%0A%0D%0Aunion+all%0D%0A%0D%0Aselect+upper%28%22DOG_NAME%22%29+as+name+from+%5Bburnside-dog-registrations-2015%5D+where+DOG_BREED+like+%3Abreed%0D%0A%0D%0Aunion+all+%0D%0A%0D%0Aselect+upper%28%22Animal_Name%22%29+as+name+from+%5Bcity-of-playford-2015-dog-registration%5D+where+Breed_Description+like+%3Abreed%0D%0A%0D%0Aunion+all%0D%0A%0D%0Aselect+upper%28%22Animal+Name%22%29+as+name+from+%5Bcity-of-prospect-dog-registration-details-2016%5D+where%22Breed+Description%22+like+%3Abreed%0D%0A%0D%0A%29+group+by+name+order+by+n+desc%3B&breed=pug", "label": "Here’s an example"}, {"href": "https://github.com/simonw/datasette/issues/100", "label": "#100"}, {"href": "https://github.com/simonw/datasette/issues/98", "label": "#98"}, {"href": "https://github.com/simonw/datasette/issues/92", "label": "#92"}, {"href": "https://github.com/simonw/datasette/issues/94", "label": "#94"}, {"href": "https://github.com/simonw/datasette/issues/95", "label": "#95"}, {"href": "https://github.com/simonw/datasette/issues/89", "label": "#89"}]


id: changelog:id205
page: changelog
ref: id205
title: 0.11 (2017-11-14)
breadcrumbs: ["Changelog"]
references: []
content:
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.


id: changelog:id206
page: changelog
ref: id206
title: 0.10 (2017-11-14)
breadcrumbs: ["Changelog"]
references: [{"href": "https://github.com/simonw/datasette/issues/83", "label": "#83"}]
content:
Fixed  #83  - 500 error on individual row pages. 
                 
                 
                     Stop using sqlite WITH RECURSIVE in our tests. 
                     The version of Python 3 running in Travis CI doesn't support this.


id: changelog:id208
page: changelog
ref: id208
title: 0.9 (2017-11-13)
breadcrumbs: ["Changelog"]
references: []
content:
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.


id: changelog:id209
page: changelog
ref: id209
title: 0.8 (2017-11-13)
breadcrumbs: ["Changelog"]
content:
V0.8 - added PyPI metadata, ready to ship. 
                 
                 
                     Implemented offset/limit pagination for views ( #70 ). 
                 
                 
                     Improved pagination. ( #78 ) 
                 
                 
                     Limit on max rows returned, controlled by  --max_returned_rows  option. ( #69 ) 
                     If someone executes 'select * from table' against a table with a million rows
                        in it, we could run into problems: just serializing that much data as JSON is
                        likely to lock up the server. 
                     Solution: we now have a hard limit on the maximum number of rows that can be
                        returned by a query. If that limit is exceeded, the server will return a
                         "truncated": true  field in the JSON. 
                     This limit can be optionally controlled by the new  --max_returned_rows 
                        option. Setting that option to 0 disables the limit entirely.

references:
[{"href": "https://github.com/simonw/datasette/issues/70", "label": "#70"}, {"href": "https://github.com/simonw/datasette/issues/78", "label": "#78"}, {"href": "https://github.com/simonw/datasette/issues/69", "label": "#69"}]


id: index:datasette
page: index
ref: datasette
title: Datasette
breadcrumbs: []
content:
An open source multi-tool for exploring and publishing data 
         Datasette is a tool for exploring and publishing data. It helps people take data of any shape or size and publish that as an interactive, explorable website and accompanying API. 
         Datasette is aimed at data journalists, museum curators, archivists, local governments and anyone else who has data that they wish to share with the world. It is part of a  wider ecosystem of tools and plugins  dedicated to making working with structured data as productive as possible. 
         Explore a demo , watch  a presentation about the project  or  Try Datasette without installing anything using Glitch . 
         Interested in learning Datasette? Start with  the official tutorials . 
         Support questions, feedback? Join our  GitHub Discussions forum .

references:
[{"href": "https://pypi.org/project/datasette/", "label": null}, {"href": "https://docs.datasette.io/en/stable/changelog.html", "label": null}, {"href": "https://pypi.org/project/datasette/", "label": null}, {"href": "https://github.com/simonw/datasette/actions?query=workflow%3ATest", "label": null}, {"href": "https://github.com/simonw/datasette/blob/main/LICENSE", "label": null}, {"href": "https://hub.docker.com/r/datasetteproject/datasette", "label": null}, {"href": "https://discord.gg/ktd74dm5mw", "label": null}, {"href": "https://pypi.org/project/datasette/", "label": null}, {"href": "https://docs.datasette.io/en/stable/changelog.html", "label": null}, {"href": "https://pypi.org/project/datasette/", "label": null}, {"href": "https://github.com/simonw/datasette/actions?query=workflow%3ATest", "label": null}, {"href": "https://github.com/simonw/datasette/blob/main/LICENSE", "label": null}, {"href": "https://hub.docker.com/r/datasetteproject/datasette", "label": null}, {"href": "https://discord.gg/ktd74dm5mw", "label": null}, {"href": "https://fivethirtyeight.datasettes.com/fivethirtyeight", "label": "Explore a demo"}, {"href": "https://static.simonwillison.net/static/2018/pybay-datasette/", "label": "a presentation about the project"}, {"href": "https://datasette.io/tutorials", "label": "the official tutorials"}, {"href": "https://github.com/simonw/datasette/discussions", "label": "GitHub Discussions forum"}]


id: index:contents
page: index
ref: contents
title: Contents
breadcrumbs: ["Datasette"]
references: []
content:
Getting started Play with a live demo Follow a tutorial Datasette in your browser with Datasette Lite Try Datasette without installing anything using Glitch Using Datasette on your own computer Installation Basic installation Datasette Desktop for Mac Using Homebrew Using pip Advanced installation options Using pipx Using Docker A note about extensions The Datasette Ecosystem sqlite-utils Dogsheep CLI reference datasette --help datasette serve datasette --get datasette serve --help-settings datasette plugins datasette install datasette uninstall datasette publish datasette publish cloudrun datasette publish heroku datasette package datasette inspect Pages and API endpoints Top-level index Database Table Row Publishing data datasette publish Publishing to Google Cloud Run Publishing to Heroku Publishing to Vercel Publishing to Fly Custom metadata and plugins datasette package Deploying Datasette Deployment fundamentals Running Datasette using systemd Running Datasette using OpenRC Deploying using buildpacks Running Datasette behind a proxy Nginx proxy configuration Apache proxy configuration JSON API Different shapes Pagination Special JSON arguments Table arguments Column filter arguments Special table arguments Expanding foreign key references Discovering the JSON for a page Running SQL queries Named parameters Views Canned queries Canned query parameters Additional canned query options Writable canned queries Magic parameters JSON API for writable canned queries Pagination Cross-database queries Authentication and permissions Actors Using the "root" actor Permissions Defining permissions with "allow" blocks The /-/allow-debug tool Configuring permissions in metadata.json Controlling access to an instance Controlling access to specific databases Controlling access to specific tables and views Controlling access to specific canned queries Controlling the ability to execute arbitrary SQL Checking permissions in plugins actor_matches_allow() The permissions debug tool The ds_actor cookie Including an expiry time The /-/logout page Built-in permissions view-instance view-database view-database-download view-table view-query execute-sql permissions-debug debug-menu Performance and caching Immutable mode Using "datasette inspect" HTTP caching datasette-hashed-urls CSV export URL parameters Streaming all records Binary data Linking to binary downloads Binary plugins Facets Facets in query strings Facets in metadata.json Suggested facets Speeding up facets with indexes Facet by JSON array Facet by date Full-text search The table page and table view API Advanced SQLite search queries Configuring full-text search for a table or view Searches using custom SQL Enabling full-text search for a SQLite table Configuring FTS using sqlite-utils Configuring FTS using csvs-to-sqlite Configuring FTS by hand FTS versions SpatiaLite Warning Installation Installing SpatiaLite on OS X Installing SpatiaLite on Linux Spatial indexing latitude/longitude columns Making use of a spatial index Importing shapefiles into SpatiaLite Importing GeoJSON polygons using Shapely Querying polygons using within() Metadata Per-database and per-table metadata Source, license and about Column descriptions Specifying units for a column Setting a default sort order Setting a custom page size Setting which columns can be used for sorting Specifying the label column for a table Hiding tables Using YAML for metadata Settings Using --setting Configuration directory mode Settings default_allow_sql default_page_size sql_time_limit_ms max_returned_rows num_sql_threads allow_facet default_facet_size facet_time_limit_ms facet_suggest_time_limit_ms suggest_facets allow_download default_cache_ttl cache_size_kb allow_csv_stream max_csv_mb truncate_cells_html force_https_urls template_debug trace_debug base_url Configuring the secret Using secrets with datasette publish Introspection /-/metadata /-/versions /-/plugins /-/settings /-/databases /-/threads /-/actor /-/messages Custom pages and templates Custom CSS and JavaScript CSS classes on the <body> Serving static files Publishing static assets Custom templates Custom pages Path parameters for pages Custom headers and status codes Returning 404s Custom redirects Custom error pages Plugins Installing plugins One-off plugins using --plugins-dir Deploying plugins using datasette publish Seeing what plugins are installed Plugin configuration Secret configuration values Writing plugins Writing one-off plugins Starting an installable plugin using cookiecutter Packaging a plugin Static assets Custom templates Writing plugins that accept configuration Designing URLs for your plugin Building URLs within plugins Plugin hooks prepare_connection(conn, database, datasette) prepare_jinja2_environment(env, datasette) 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) register_output_renderer(datasette) register_routes(datasette) register_commands(cli) register_facet_classes() asgi_wrapper(datasette) startup(datasette) canned_queries(datasette, database, actor) actor_from_request(datasette, request) 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) menu_links(datasette, actor, request) table_actions(datasette, actor, database, table, request) database_actions(datasette, actor, database, request) skip_csrf(datasette, scope) get_metadata(datasette, key, database, table) Testing plugins Setting up a Datasette test instance Using pdb for errors thrown inside Datasette Using pytest fixtures Testing outbound HTTP calls with pytest-httpx Registering a plugin for the duration of a test Internals for plugins Request object The MultiParams class Response class Returning a response with .asgi_send(send) Setting cookies with response.set_cookie() Datasette class .databases .plugin_config(plugin_name, database=None, table=None) await .render_template(template, context=None, request=None) await .permission_allowed(actor, action, resource=None, default=False) await .ensure_permissions(actor, permissions) await .check_visibility(actor, action=None, resource=None, permissions=None) .get_database(name) .add_database(db, name=None, route=None) .add_memory_database(name) .remove_database(name) .sign(value, namespace="default") .unsign(value, namespace="default") .add_message(request, message, type=datasette.INFO) .absolute_url(request, path) .setting(key) datasette.client datasette.urls Database class Database(ds, path=None, is_mutable=True, is_memory=False, memory_name=None) db.hash await db.execute(sql, ...) Results await db.execute_fn(fn) await db.execute_write(sql, params=None, block=True) await db.execute_write_script(sql, block=True) await db.execute_write_many(sql, params_seq, block=True) await db.execute_write_fn(fn, block=True) db.close() Database introspection CSRF protection The _internal database The datasette.utils module parse_metadata(content) await_me_maybe(value) Tilde encoding datasette.tracer Tracing child tasks Import shortcuts Contributing General guidelines Setting up a development environment Running the tests Using fixtures Debugging Code formatting Running Black blacken-docs Prettier Editing and building the documentation Running Cog Continuously deployed demo instances Release process Alpha and beta releases Releasing bug fixes from a branch Upgrading CodeMirror Changelog 0.64.6 (2023-12-22) 0.64.5 (2023-10-08) 0.64.4 (2023-09-21) 0.64.3 (2023-04-27) 0.64.2 (2023-03-08) 0.64.1 (2023-01-11) 0.64 (2023-01-09) 0.63.3 (2022-12-17) 0.63.2 (2022-11-18) 0.63.1 (2022-11-10) 0.63 (2022-10-27) Features Plugin hooks and internals Documentation 0.62 (2022-08-14) Features Plugin hooks Bug fixes Documentation 0.61.1 (2022-03-23) 0.61 (2022-03-23) 0.60.2 (2022-02-07) 0.60.1 (2022-01-20) 0.60 (2022-01-13) Plugins and internals Faceting Other small fixes 0.59.4 (2021-11-29) 0.59.3 (2021-11-20) 0.59.2 (2021-11-13) 0.59.1 (2021-10-24) 0.59 (2021-10-14) 0.58.1 (2021-07-16) 0.58 (2021-07-14) 0.57.1 (2021-06-08) 0.57 (2021-06-05) New features Bug fixes and other improvements 0.56.1 (2021-06-05) 0.56 (2021-03-28) 0.55 (2021-02-18) 0.54.1 (2021-02-02) 0.54 (2021-01-25) The _internal database Named in-memory database support JavaScript modules Code formatting with Black and Prettier Other changes 0.53 (2020-12-10) 0.52.5 (2020-12-09) 0.52.4 (2020-12-05) 0.52.3 (2020-12-03) 0.52.2 (2020-12-02) 0.52.1 (2020-11-29) 0.52 (2020-11-28) 0.51.1 (2020-10-31) 0.51 (2020-10-31) New visual design Plugins can now add links within Datasette Binary data URL building Running Datasette behind a proxy Smaller changes 0.50.2 (2020-10-09) 0.50.1 (2020-10-09) 0.50 (2020-10-09) 0.49.1 (2020-09-15) 0.49 (2020-09-14) 0.48 (2020-08-16) 0.47.3 (2020-08-15) 0.47.2 (2020-08-12) 0.47.1 (2020-08-11) 0.47 (2020-08-11) 0.46 (2020-08-09) 0.45 (2020-07-01) Magic parameters for canned queries Log out Better plugin documentation New plugin hooks Smaller changes 0.44 (2020-06-11) Authentication Permissions Writable canned queries Flash messages Signed values and secrets CSRF protection Cookie methods register_routes() plugin hooks Smaller changes The road to Datasette 1.0 0.43 (2020-05-28) 0.42 (2020-05-08) 0.41 (2020-05-06) 0.40 (2020-04-21) 0.39 (2020-03-24) 0.38 (2020-03-08) 0.37.1 (2020-03-02) 0.37 (2020-02-25) 0.36 (2020-02-21) 0.35 (2020-02-04) 0.34 (2020-01-29) 0.33 (2019-12-22) 0.32 (2019-11-14) 0.31.2 (2019-11-13) 0.31.1 (2019-11-12) 0.31 (2019-11-11) 0.30.2 (2019-11-02) 0.30.1 (2019-10-30) 0.30 (2019-10-18) 0.29.3 (2019-09-02) 0.29.2 (2019-07-13) 0.29.1 (2019-07-11) 0.29 (2019-07-07) ASGI New plugin hook: asgi_wrapper New plugin hook: extra_template_vars Secret plugin configuration options Facet by date Easier custom templates for table rows ?_through= for joins through many-to-many tables Small changes 0.28 (2019-05-19) Supporting databases that change Faceting improvements, and faceting plugins datasette publish cloudrun register_output_renderer plugins Medium changes Small changes 0.27.1 (2019-05-09) 0.27 (2019-01-31) 0.26.1 (2019-01-10) 0.26 (2019-01-02) 0.25.2 (2018-12-16) 0.25.1 (2018-11-04) 0.25 (2018-09-19) 0.24 (2018-07-23) 0.23.2 (2018-07-07) 0.23.1 (2018-06-21) 0.23 (2018-06-18) CSV export Foreign key expansions New configuration settings Control HTTP caching with ?_ttl= Improved support for SpatiaLite latest.datasette.io Miscellaneous 0.22.1 (2018-05-23) 0.22 (2018-05-20) 0.21 (2018-05-05) 0.20 (2018-04-20) 0.19 (2018-04-16) 0.18 (2018-04-14) 0.17 (2018-04-13) 0.16 (2018-04-13) 0.15 (2018-04-09) 0.14 (2017-12-09) 0.13 (2017-11-24) 0.12 (2017-11-16) 0.11 (2017-11-14) 0.10 (2017-11-14) 0.9 (2017-11-13) 0.8 (2017-11-13)


id: cli-reference:id1
page: cli-reference
ref: id1
title: CLI reference
breadcrumbs: []
references: []
content:
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]]]


id: cli-reference:cli-help-help
page: cli-reference
ref: cli-help-help
title: datasette --help
breadcrumbs: ["CLI reference"]
references: []
content:
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
  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 along...
  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.


id: cli-reference:cli-help-serve-help
page: cli-reference
ref: cli-help-serve-help
title: datasette serve
breadcrumbs: ["CLI reference"]
references: []
content:
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
  --config CONFIG                 Deprecated: set config option using
                                  configname:value. Use --setting instead.
  --setting SETTING...            Setting, see
                                  docs.datasette.io/en/stable/settings.html
  --secret TEXT                   Secret used for signing secure values, such as
                                  signed cookies
  --root                          Output URL that sets a cookie authenticating
                                  the root user
  --get TEXT                      Run an HTTP GET request against this path,
                                  print results and exit
  --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
  --help                          Show this message and exit. 
             [[[end]]]


id: cli-reference:cli-datasette-get
page: cli-reference
ref: cli-datasette-get
title: datasette --get
breadcrumbs: ["CLI reference", "datasette serve"]
references: []
content:
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"
    ]
  }
} 
                 The exit code 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.


id: cli-reference:cli-help-serve-help-settings
page: cli-reference
ref: cli-help-serve-help-settings
title: datasette serve --help-settings
breadcrumbs: ["CLI reference", "datasette serve"]
references: []
content:
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)
  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)
  default_allow_sql            Allow anyone to run arbitrary SQL queries
                               (default=True)
  allow_download               Allow users to download the original SQLite
                               database files (default=True)
  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]]]


id: cli-reference:cli-help-plugins-help
page: cli-reference
ref: cli-help-plugins-help
title: datasette plugins
breadcrumbs: ["CLI reference"]
references: []
content:
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
  --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"
        ]
    }
]


id: cli-reference:cli-help-install-help
page: cli-reference
ref: cli-help-install-help
title: datasette install
breadcrumbs: ["CLI reference"]
references: [{"href": "https://datasette.io/plugins/datasette-cluster-map", "label": "datasette-cluster-map"}]
content:
Install new Datasette plugins. This command works like  pip install  but ensures that your plugins will be installed into the same environment as Datasette. 
             This command: 
             datasette install datasette-cluster-map 
             Would install the  datasette-cluster-map  plugin. 
             [[[cog
help(["install", "--help"]) 
             ]]] 
             Usage: datasette install [OPTIONS] PACKAGES...

  Install plugins and packages from PyPI into the same environment as Datasette

Options:
  -U, --upgrade  Upgrade packages to latest version
  --help         Show this message and exit. 
             [[[end]]]


id: cli-reference:cli-help-uninstall-help
page: cli-reference
ref: cli-help-uninstall-help
title: datasette uninstall
breadcrumbs: ["CLI reference"]
references: []
content:
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]]]


id: cli-reference:cli-help-publish-help
page: cli-reference
ref: cli-help-publish-help
title: datasette publish
breadcrumbs: ["CLI reference"]
references: []
content:
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]]]


id: cli-reference:cli-help-publish-cloudrun-help
page: cli-reference
ref: cli-help-publish-cloudrun-help
title: datasette publish cloudrun
breadcrumbs: ["CLI reference"]
references: []
content:
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 <TEXT TEXT TEXT>...
                                  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
  --min-instances INTEGER         Minimum Cloud Run instances
  --help                          Show this message and exit. 
             [[[end]]]


id: cli-reference:cli-help-publish-heroku-help
page: cli-reference
ref: cli-help-publish-heroku-help
title: datasette publish heroku
breadcrumbs: ["CLI reference"]
references: []
content:
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 <TEXT TEXT TEXT>...
                                  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]]]


id: cli-reference:cli-help-package-help
page: cli-reference
ref: cli-help-package-help
title: datasette package
breadcrumbs: ["CLI reference"]
references: []
content:
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]]]


id: cli-reference:cli-help-inspect-help
page: cli-reference
ref: cli-help-inspect-help
title: datasette inspect
breadcrumbs: ["CLI reference"]
references: []
content:
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]]]


id: authentication:authentication
page: authentication
ref: authentication
title: Authentication and permissions
breadcrumbs: []
references: []
content:
Datasette does not require authentication by default. Any visitor to a Datasette instance can explore the full data and execute read-only SQL queries. 
         Datasette's plugin system can be used to add many different styles of authentication, such as user accounts, single sign-on or API keys.


id: authentication:authentication-actor
page: authentication
ref: authentication-actor
title: Actors
breadcrumbs: ["Authentication and permissions"]
references: []
content:
Through plugins, Datasette can support both authenticated users (with cookies) and authenticated API agents (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 agents. 
             The actor dictionary can be any shape - the design of that data structure is left up to the plugins. A useful convention is to include an  "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.


id: authentication:authentication-root
page: authentication
ref: authentication-root
title: Using the "root" actor
breadcrumbs: ["Authentication and permissions", "Actors"]
references: [{"href": "https://github.com/simonw/datasette-auth-github", "label": "datasette-auth-github"}]
content:
Datasette currently leaves almost all forms of authentication to plugins -  datasette-auth-github  for example. 
                 The one exception is the "root" account, which you can sign into while using Datasette on your local machine. This provides access to a small number of debugging features. 
                 To sign in as root, start Datasette using the  --root  command-line option, like this: 
                 $ datasette --root
http://127.0.0.1:8001/-/auth-token?token=786fc524e0199d70dc9a581d851f466244e114ca92f33aa3b42a139e9388daa7
INFO:     Started server process [25801]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8001 (Press CTRL+C to quit) 
                 The URL on the first line includes a one-use token which can be used to sign in as the "root" actor in your browser. Click on that link and then visit  http://127.0.0.1:8001/-/actor  to confirm that you are authenticated as an actor that looks like this: 
                 {
    "id": "root"
}


id: authentication:authentication-permissions
page: authentication
ref: authentication-permissions
title: Permissions
breadcrumbs: ["Authentication and permissions"]
references: [{"href": "https://github.com/simonw/datasette-upload-csvs", "label": "datasette-upload-csvs"}]
content:
Datasette has an extensive permissions system built-in, which can be further extended and customized by plugins. 
             The key question the permissions system answers is this: 
             
                 Is this  actor  allowed to perform this  action , optionally against this particular  resource ? 
             
             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 permissions ( view-database ,  view-table  etc) default to  allow  - unless you  configure additional permission rules  unauthenticated users will be allowed to access content. 
             Permissions with potentially harmful effects should default to  deny . Plugin authors should account for this when designing new plugins - for example, the  datasette-upload-csvs  plugin defaults to deny so that installations don't accidentally allow unauthenticated users to create new tables by uploading a CSV file.


id: authentication:authentication-permissions-allow
page: authentication
ref: authentication-permissions-allow
title: Defining permissions with "allow" blocks
breadcrumbs: ["Authentication and permissions", "Permissions"]
content:
The standard way to define permissions in Datasette is to use an  "allow"  block. 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 ): 
                 {
    "allow": {
        "id": "root"
    }
} 
                 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 ): 
                 {
    "allow": false
} 
                 An  "allow"  of  true  allows all access ( demo ): 
                 {
    "allow": true
} 
                 Allow keys can provide a list of values. These will match any actor that has any of those values ( allow demo ,  deny demo ): 
                 {
    "allow": {
        "id": ["simon", "cleopaws"]
    }
} 
                 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 ): 
                 {
    "allow": {
        "roles": ["developer"]
    }
} 
                 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 ): 
                 {
    "allow": {
        "id": "*"
    }
} 
                 You can specify that only unauthenticated actors (from anynomous HTTP requests) should be allowed access using the special  "unauthenticated": true  key in an allow block ( allow demo ,  deny demo ): 
                 {
    "allow": {
        "unauthenticated": true
    }
} 
                 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" : 
                 {
    "allow": {
        "id": ["simon", "cleopaws"],
        "role": "ops"
    }
} 
                 Demo for cleopaws ,  demo for ops role ,  demo for an actor matching neither rule .

references:
[{"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"}]


id: authentication:allowdebugview
page: authentication
ref: allowdebugview
title: The /-/allow-debug tool
breadcrumbs: ["Authentication and permissions", "Permissions"]
content:
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

references:
[{"href": "https://latest.datasette.io/-/allow-debug", "label": "https://latest.datasette.io/-/allow-debug"}]


id: authentication:authentication-permissions-metadata
page: authentication
ref: authentication-permissions-metadata
title: Configuring permissions in metadata.json
breadcrumbs: ["Authentication and permissions"]
references: []
content:
You can limit who is allowed to view different parts of your Datasette instance using  "allow"  keys in your  Metadata  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  Canned queries 
                 
             
             If a user cannot access a specific database, they will not be able to access tables, views or queries within that database. If a user cannot access the instance they will not be able to access any of the databases, tables, views or queries.


id: authentication:authentication-permissions-instance
page: authentication
ref: authentication-permissions-instance
title: Controlling access to an instance
breadcrumbs: ["Authentication and permissions", "Configuring permissions in metadata.json"]
content:
Here's how to restrict access to your entire Datasette instance to just the  "id": "root"  user: 
                 {
    "title": "My private Datasette instance",
    "allow": {
        "id": "root"
    }
} 
                 To deny access to all users, you can use  "allow": false : 
                 {
    "title": "My entirely inaccessible instance",
    "allow": false
} 
                 One reason to do this is if you are using a Datasette plugin - such as  datasette-permissions-sql  - to control permissions instead.

references:
[{"href": "https://github.com/simonw/datasette-permissions-sql", "label": "datasette-permissions-sql"}]


id: authentication:authentication-permissions-database
page: authentication
ref: authentication-permissions-database
title: Controlling access to specific databases
breadcrumbs: ["Authentication and permissions", "Configuring permissions in metadata.json"]
references: []
content:
To limit access to a specific  private.db  database to just authenticated users, use the  "allow"  block like this: 
                 {
    "databases": {
        "private": {
            "allow": {
                "id": "*"
            }
        }
    }
}


id: authentication:authentication-permissions-table
page: authentication
ref: authentication-permissions-table
title: Controlling access to specific tables and views
breadcrumbs: ["Authentication and permissions", "Configuring permissions in metadata.json"]
content:
To limit access to the  users  table in your  bakery.db  database: 
                 {
    "databases": {
        "bakery": {
            "tables": {
                "users": {
                    "allow": {
                        "id": "*"
                    }
                }
            }
        }
    }
} 
                 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 .

references:
[{"href": "https://latest.datasette.io/fixtures?sql=select+*+from+facetable", "label": "like this"}]


id: authentication:authentication-permissions-query
page: authentication
ref: authentication-permissions-query
title: Controlling access to specific canned queries
breadcrumbs: ["Authentication and permissions", "Configuring permissions in metadata.json"]
references: []
content:
Canned queries  allow you to configure named SQL queries in your  metadata.json  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  canned query in your  dogs.db  database to just the  root user : 
                 {
    "databases": {
        "dogs": {
            "queries": {
                "add_name": {
                    "sql": "INSERT INTO names (name) VALUES (:name)",
                    "write": true,
                    "allow": {
                        "id": ["root"]
                    }
                }
            }
        }
    }
}


id: authentication:authentication-permissions-execute-sql
page: authentication
ref: authentication-permissions-execute-sql
title: Controlling the ability to execute arbitrary SQL
breadcrumbs: ["Authentication and permissions", "Configuring permissions in metadata.json"]
content:
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: 
                 {
    "allow_sql": false
} 
                 To enable just the  root user  to execute SQL for all databases in your instance, use the following: 
                 {
    "allow_sql": {
        "id": "root"
    }
} 
                 To limit this ability for just one specific database, use this: 
                 {
    "databases": {
        "mydatabase": {
            "allow_sql": {
                "id": "root"
            }
        }
    }
}

references:
[{"href": "https://latest.datasette.io/fixtures", "label": "the database page"}, {"href": "https://latest.datasette.io/fixtures/facetable?_where=_city_id=1", "label": "like this"}]


id: authentication:permissions-plugins
page: authentication
ref: permissions-plugins
title: Checking permissions in plugins
breadcrumbs: ["Authentication and permissions"]
references: []
content:
Datasette plugins can check if an actor has permission to perform an action using the  datasette.permission_allowed(...)  method. 
             Datasette core performs a number of permission checks,  documented below . Plugins can implement the  permission_allowed(datasette, actor, action, resource)  plugin hook to participate in decisions about whether an actor should be able to perform a specified action.


id: authentication:authentication-actor-matches-allow
page: authentication
ref: authentication-actor-matches-allow
title: actor_matches_allow()
breadcrumbs: ["Authentication and permissions"]
references: []
content:
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 .


id: authentication:permissionsdebugview
page: authentication
ref: permissionsdebugview
title: The permissions debug tool
breadcrumbs: ["Authentication and permissions"]
references: []
content:
The debug tool at  /-/permissions  is only available to the  authenticated root user  (or any actor granted the  permissions-debug  action according to a plugin). 
             It shows the thirty most recent permission checks that have been carried out by the Datasette instance. 
             This is designed to help administrators and plugin authors understand exactly how permission checks are being carried out, in order to effectively configure Datasette's permission system.


id: authentication:authentication-ds-actor
page: authentication
ref: authentication-ds-actor
title: The ds_actor cookie
breadcrumbs: ["Authentication and permissions"]
references: []
content:
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("/")
response.set_cookie(
    "ds_actor",
    datasette.sign({"a": {"id": "cleopaws"}}, "actor"),
) 
             Note that you need to pass  "actor"  as the namespace to  .sign(value, namespace="default") . 
             The shape of data encoded in the cookie is as follows: 
             {
    "a": {... actor ...}
}


id: authentication:authentication-ds-actor-expiry
page: authentication
ref: authentication-ds-actor-expiry
title: Including an expiry time
breadcrumbs: ["Authentication and permissions", "The ds_actor cookie"]
references: []
content:
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, add a  "e"  key to the cookie value containing a base62-encoded integer representing the timestamp when the cookie should expire. For example, here's how to set a cookie that expires after 24 hours: 
                 import time
from datasette.utils import baseconv

expires_at = int(time.time()) + (24 * 60 * 60)

response = Response.redirect("/")
response.set_cookie(
    "ds_actor",
    datasette.sign(
        {
            "a": {"id": "cleopaws"},
            "e": baseconv.base62.encode(expires_at),
        },
        "actor",
    ),
) 
                 The resulting cookie will encode data that looks something like this: 
                 {
    "a": {
        "id": "cleopaws"
    },
    "e": "1jjSji"
}


id: authentication:logoutview
page: authentication
ref: logoutview
title: The /-/logout page
breadcrumbs: ["Authentication and permissions", "The ds_actor cookie"]
references: []
content:
The page at  /-/logout  provides the ability to log out of a  ds_actor  cookie authentication session.


id: authentication:id1
page: authentication
ref: id1
title: Built-in permissions
breadcrumbs: ["Authentication and permissions"]
references: []
content:
This section lists all of the permission checks that are carried out by Datasette core, along with the  resource  if it was passed.


id: authentication:permissions-view-instance
page: authentication
ref: permissions-view-instance
title: view-instance
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
references: [{"href": "https://latest.datasette.io/", "label": "https://latest.datasette.io/"}]
content:
Top level permission - Actor is allowed to view any pages within this instance, starting at  https://latest.datasette.io/ 
                 Default  allow .


id: authentication:permissions-view-database
page: authentication
ref: permissions-view-database
title: view-database
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
references: [{"href": "https://latest.datasette.io/fixtures", "label": "https://latest.datasette.io/fixtures"}]
content:
Actor is allowed to view a database page, e.g.  https://latest.datasette.io/fixtures 
                 
                     
                         resource  - string 
                         
                             The name of the database 
                         
                     
                 
                 Default  allow .


id: authentication:permissions-view-database-download
page: authentication
ref: permissions-view-database-download
title: view-database-download
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
content:
Actor is allowed to download a database, e.g.  https://latest.datasette.io/fixtures.db 
                 
                     
                         resource  - string 
                         
                             The name of the database 
                         
                     
                 
                 Default  allow .

references:
[{"href": "https://latest.datasette.io/fixtures.db", "label": "https://latest.datasette.io/fixtures.db"}]


id: authentication:permissions-view-table
page: authentication
ref: permissions-view-table
title: view-table
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
content:
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 .

references:
[{"href": "https://latest.datasette.io/fixtures/complex_foreign_keys", "label": "https://latest.datasette.io/fixtures/complex_foreign_keys"}]


id: authentication:permissions-view-query
page: authentication
ref: permissions-view-query
title: view-query
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
content:
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 .

references:
[{"href": "https://latest.datasette.io/fixtures/pragma_cache_size", "label": "https://latest.datasette.io/fixtures/pragma_cache_size"}]


id: authentication:permissions-execute-sql
page: authentication
ref: permissions-execute-sql
title: execute-sql
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
content:
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 .

references:
[{"href": "https://latest.datasette.io/fixtures?sql=select+100", "label": "https://latest.datasette.io/fixtures?sql=select+100"}]


id: authentication:permissions-debug-menu
page: authentication
ref: permissions-debug-menu
title: debug-menu
breadcrumbs: ["Authentication and permissions", "Built-in permissions"]
references: []
content:
Controls if the various debug pages are displayed in the navigation menu. 
                 Default  deny .


id: binary_data:binary
page: binary_data
ref: binary
title: Binary data
breadcrumbs: []
content:
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
    }
]

references:
[{"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"}]


id: binary_data:binary-linking
page: binary_data
ref: binary-linking
title: Linking to binary downloads
breadcrumbs: ["Binary data"]
content:
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.

references:
[{"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"}]


id: binary_data:binary-plugins
page: binary_data
ref: binary-plugins
title: Binary plugins
breadcrumbs: ["Binary data"]
content:
Several Datasette plugins are available that change the way Datasette treats binary data. 
             
                 
                     datasette-render-binary  modifies Datasette's default interface to show an automatic guess at what type of binary data is being stored, along with a visual representation of the binary value that displays ASCII strings directly in the interface. 
                 
                 
                     datasette-render-images  detects common image formats and renders them as images directly in the Datasette interface. 
                 
                 
                     datasette-media  allows Datasette interfaces to be configured to serve binary files from configured SQL queries, and includes the ability to resize images directly before serving them.

references:
[{"href": "https://github.com/simonw/datasette-render-binary", "label": "datasette-render-binary"}, {"href": "https://github.com/simonw/datasette-render-images", "label": "datasette-render-images"}, {"href": "https://github.com/simonw/datasette-media", "label": "datasette-media"}]


id: sql_queries:sql
page: sql_queries
ref: sql
title: Running SQL queries
breadcrumbs: []
references: []
content:
Datasette treats SQLite database files as read-only and immutable. This means it is not possible to execute INSERT or UPDATE statements using Datasette, which allows us to expose SELECT statements to the outside world without needing to worry about SQL injection attacks. 
         The easiest way to execute custom SQL against Datasette is through the web UI. The database index page includes a SQL editor that lets you run any SELECT query you like. You can also construct queries using the filter interface on the tables page, then click "View and edit SQL" to open that query in the custom SQL editor. 
         Note that this interface is only available if the  execute-sql  permission is allowed. 
         Any Datasette SQL query is reflected in the URL of the page, allowing you to bookmark them, share them with others and navigate through previous queries using your browser back button. 
         You can also retrieve the results of any query as JSON by adding  .json  to the base URL.


id: sql_queries:sql-parameters
page: sql_queries
ref: sql-parameters
title: Named parameters
breadcrumbs: ["Running SQL queries"]
references: [{"href": "https://github.com/simonw/datasette/issues/761", "label": "of exceptions"}]
content:
Datasette has special support for SQLite named parameters. Consider a SQL query like this: 
             select * from Street_Tree_List
where "PermitNotes" like :notes
and "qSpecies" = :species 
             If you execute this query using the custom query editor, Datasette will extract the two named parameters and use them to construct form fields for you to provide values. 
             You can also provide values for these fields by constructing a URL: 
             /mydatabase?sql=select...&species=44 
             SQLite string escaping rules will be applied to values passed using named parameters - they will be wrapped in quotes and their content will be correctly escaped. 
             Values from named parameters are treated as SQLite strings. If you need to perform numeric comparisons on them you should cast them to an integer or float first using  cast(:name as integer)  or  cast(:name as real) , for example: 
             select * from Street_Tree_List
where latitude > cast(:min_latitude as real)
and latitude < cast(:max_latitude as real) 
             Datasette disallows custom SQL queries containing the string PRAGMA (with a small number  of exceptions ) as SQLite pragma statements can be used to change database settings at runtime. If you need to include the string "pragma" in a query you can do so safely using a named parameter.


id: sql_queries:sql-views
page: sql_queries
ref: sql-views
title: Views
breadcrumbs: ["Running SQL queries"]
references: []
content:
If you want to bundle some pre-written SQL queries with your Datasette-hosted database you can do so in two ways. The first is to include SQL views in your database - Datasette will then list those views on your database index page. 
             The quickest way to create views is with the SQLite command-line interface: 
             $ sqlite3 sf-trees.db
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> CREATE VIEW demo_view AS select qSpecies from Street_Tree_List;
<CTRL+D>


id: sql_queries:id1
page: sql_queries
ref: id1
title: Canned queries
breadcrumbs: ["Running SQL queries"]
references: []
content:
As an alternative to adding views to your database, you can define canned queries inside your  metadata.json  file. Here's an example: 
             {
    "databases": {
       "sf-trees": {
           "queries": {
               "just_species": {
                   "sql": "select qSpecies from Street_Tree_List"
               }
           }
       }
    }
} 
             Then run Datasette like this: 
             datasette sf-trees.db -m metadata.json 
             Each canned query will be listed on the database index page, and will also get its own URL at: 
             /database-name/canned-query-name 
             For the above example, that URL would be: 
             /sf-trees/just_species 
             You can optionally include  "title"  and  "description"  keys to show a title and description on the canned query page. As with regular table metadata you can alternatively specify  "description_html"  to have your description rendered as HTML (rather than having HTML special characters escaped).


id: sql_queries:canned-queries-named-parameters
page: sql_queries
ref: canned-queries-named-parameters
title: Canned query parameters
breadcrumbs: ["Running SQL queries", "Canned queries"]
content:
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 metadata (here  Using YAML for metadata  as  metadata.yaml ) it looks like this: 
                 databases:
  fixtures:
    queries:
      neighborhood_search:
        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
        title: Search neighborhoods 
                 Here's the equivalent using JSON (as  metadata.json ): 
                 {
    "databases": {
        "fixtures": {
            "queries": {
                "neighborhood_search": {
                    "sql": "select neighborhood, facet_cities.name, state\nfrom facetable\n  join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%'\norder by neighborhood",
                    "title": "Search neighborhoods"
                }
            }
        }
    }
} 
                 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: 
                 databases:
  fixtures:
    queries:
      neighborhood_search:
        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
        title: Search neighborhoods

references:
[{"href": "https://latest.datasette.io/fixtures/neighborhood_search?text=town", "label": "https://latest.datasette.io/fixtures/neighborhood_search?text=town"}]


id: sql_queries:hide-sql
page: sql_queries
ref: hide-sql
title: hide_sql
breadcrumbs: ["Running SQL queries", "Canned queries", "Additional canned query options"]
references: []
content:
Canned queries default to displaying their SQL query at the top of the page. If the query is extremely long you may want to hide it by default, with a "show" link that can be used to make it visible. 
                     Add the  "hide_sql": true  option to hide the SQL query by default.


id: sql_queries:fragment
page: sql_queries
ref: fragment
title: fragment
breadcrumbs: ["Running SQL queries", "Canned queries", "Additional canned query options"]
content:
Some plugins, such as  datasette-vega , can be configured by including additional data in the fragment hash of the URL - the bit that comes after a  #  symbol. 
                     You can set a default fragment hash that will be included in the link to the canned query from the database index page using the  "fragment"  key. 
                     This example demonstrates both  fragment  and  hide_sql : 
                     {
    "databases": {
        "fixtures": {
            "queries": {
                "neighborhood_search": {
                    "sql": "select neighborhood, facet_cities.name, state\nfrom facetable join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%' order by neighborhood;",
                    "fragment": "fragment-goes-here",
                    "hide_sql": true
                }
            }
        }
    }
} 
                     See here  for a demo of this in action.

references:
[{"href": "https://github.com/simonw/datasette-vega", "label": "datasette-vega"}, {"href": "https://latest.datasette.io/fixtures#queries", "label": "See here"}]


id: sql_queries:canned-queries-writable
page: sql_queries
ref: canned-queries-writable
title: Writable canned queries
breadcrumbs: ["Running SQL queries", "Canned queries"]
references: []
content:
Canned queries by default are read-only. You can use the  "write": true  key to indicate that a canned query can write to the database. 
                 See  Controlling access to specific canned queries  for details on how to add permission checks to canned queries, using the  "allow"  key. 
                 {
    "databases": {
        "mydatabase": {
            "queries": {
                "add_name": {
                    "sql": "INSERT INTO names (name) VALUES (:name)",
                    "write": true
                }
            }
        }
    }
} 
                 This configuration will create a page at  /mydatabase/add_name  displaying a form with a  name  field. Submitting that form will execute the configured  INSERT  query. 
                 You can customize how Datasette represents success and errors using the following optional properties: 
                 
                     
                         on_success_message  - the message shown when a query is successful 
                     
                     
                         on_success_redirect  - the path or URL the user is redirected to on success 
                     
                     
                         on_error_message  - the message shown when a query throws an error 
                     
                     
                         on_error_redirect  - the path or URL the user is redirected to on error 
                     
                 
                 For example: 
                 {
    "databases": {
        "mydatabase": {
            "queries": {
                "add_name": {
                    "sql": "INSERT INTO names (name) VALUES (:name)",
                    "write": true,
                    "on_success_message": "Name inserted",
                    "on_success_redirect": "/mydatabase/names",
                    "on_error_message": "Name insert failed",
                    "on_error_redirect": "/mydatabase"
                }
            }
        }
    }
} 
                 You can use  "params"  to explicitly list the named parameters that should be displayed as form fields - otherwise they will be automatically detected. 
                 You can pre-populate form fields when the page first loads using a query string, e.g.  /mydatabase/add_name?name=Prepopulated . The user will have to submit the form to execute the query.


id: sql_queries:canned-queries-magic-parameters
page: sql_queries
ref: canned-queries-magic-parameters
title: Magic parameters
breadcrumbs: ["Running SQL queries", "Canned queries"]
references: []
content:
Named parameters that start with an underscore are special: they can be used to automatically add values created by Datasette that are not contained in the incoming form fields or query string. 
                 These magic parameters are only supported for canned queries: to avoid security issues (such as queries that extract the user's private cookies) they are not available to SQL that is executed by the user as a custom SQL query. 
                 Available magic parameters are: 
                 
                     
                         _actor_*  - e.g.  _actor_id ,  _actor_name 
                         
                             Fields from the currently authenticated  Actors . 
                         
                     
                     
                         _header_*  - e.g.  _header_user_agent 
                         
                             Header from the incoming HTTP request. The key should be in lower case and with hyphens converted to underscores e.g.  _header_user_agent  or  _header_accept_language . 
                         
                     
                     
                         _cookie_*  - e.g.  _cookie_lang 
                         
                             The value of the incoming cookie of that name. 
                         
                     
                     
                         _now_epoch 
                         
                             The number of seconds since the Unix epoch. 
                         
                     
                     
                         _now_date_utc 
                         
                             The date in UTC, e.g.  2020-06-01 
                         
                     
                     
                         _now_datetime_utc 
                         
                             The ISO 8601 datetime in UTC, e.g.  2020-06-24T18:01:07Z 
                         
                     
                     
                         _random_chars_*  - e.g.  _random_chars_128 
                         
                             A random string of characters of the specified length. 
                         
                     
                 
                 Here's an example configuration (this time using  metadata.yaml  since that provides better support for multi-line SQL queries) that adds a message from the authenticated user, storing various pieces of additional metadata using magic parameters: 
                 databases:
  mydatabase:
    queries:
      add_message:
        allow:
          id: "*"
        sql: |-
          INSERT INTO messages (
            user_id, message, datetime
          ) VALUES (
            :_actor_id, :message, :_now_datetime_utc
          )
        write: true 
                 The form presented at  /mydatabase/add_message  will have just a field for  message  - the other parameters will be populated by the magic parameter mechanism. 
                 Additional custom magic parameters can be added by plugins using the  register_magic_parameters(datasette)  hook.


id: sql_queries:canned-queries-json-api
page: sql_queries
ref: canned-queries-json-api
title: JSON API for writable canned queries
breadcrumbs: ["Running SQL queries", "Canned queries"]
references: []
content:
Writable canned queries can also be accessed using a JSON API. You can POST data to them using JSON, and you can request that their response is returned to you as JSON. 
                 To submit JSON to a writable canned query, encode key/value parameters as a JSON document: 
                 POST /mydatabase/add_message

{"message": "Message goes here"} 
                 You can also continue to submit data using regular form encoding, like so: 
                 POST /mydatabase/add_message

message=Message+goes+here 
                 There are three options for specifying that you would like the response to your request to return JSON data, as opposed to an HTTP redirect to another page. 
                 
                     
                         Set an  Accept: application/json  header on your request 
                     
                     
                         Include  ?_json=1  in the URL that you POST to 
                     
                     
                         Include  "_json": 1  in your JSON body, or  &_json=1  in your form encoded body 
                     
                 
                 The JSON response will look like this: 
                 {
    "ok": true,
    "message": "Query executed, 1 row affected",
    "redirect": "/data/add_name"
} 
                 The  "message"  and  "redirect"  values here will take into account  on_success_message ,  on_success_redirect ,  on_error_message  and  on_error_redirect , if they have been set.


id: sql_queries:id2
page: sql_queries
ref: id2
title: Pagination
breadcrumbs: ["Running SQL queries"]
references: []
content:
Datasette's default table pagination is designed to be extremely efficient. SQL OFFSET/LIMIT pagination can have a significant performance penalty once you get into multiple thousands of rows, as each page still requires the database to scan through every preceding row to find the correct offset. 
             When paginating through tables, Datasette instead orders the rows in the table by their primary key and performs a WHERE clause against the last seen primary key for the previous page. For example: 
             select rowid, * from Tree_List where rowid > 200 order by rowid limit 101 
             This represents page three for this particular table, with a page size of 100. 
             Note that we request 101 items in the limit clause rather than 100. This allows us to detect if we are on the last page of the results: if the query returns less than 101 rows we know we have reached the end of the pagination set. Datasette will only return the first 100 rows - the 101st is used purely to detect if there should be another page. 
             Since the where clause acts against the index on the primary key, the query is extremely fast even for records that are a long way into the overall pagination set.


id: sql_queries:id3
page: sql_queries
ref: id3
title: Cross-database queries
breadcrumbs: ["Running SQL queries"]
content:
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 .

references:
[{"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"}]


id: installation:id1
page: installation
ref: id1
title: Installation
breadcrumbs: []
references: []
content:
If you just want to try Datasette out you don't need to install anything: see  Try Datasette without installing anything using Glitch 
         
         There are two main options for installing Datasette. You can install it directly on to your machine, or you can install it using Docker. 
         If you want to start making contributions to the Datasette project by installing a copy that lets you directly modify the code, take a look at our guide to  Setting up a development environment . 
         
             
                 
                     Basic installation 
                     
                         
                             Datasette Desktop for Mac 
                         
                         
                             Using Homebrew 
                         
                         
                             Using pip 
                         
                     
                 
                 
                     Advanced installation options 
                     
                         
                             Using pipx 
                             
                                 
                                     Installing plugins using pipx 
                                 
                                 
                                     Upgrading packages using pipx 
                                 
                             
                         
                         
                             Using Docker 
                             
                                 
                                     Loading SpatiaLite 
                                 
                                 
                                     Installing plugins 
                                 
                             
                         
                     
                 
                 
                     A note about extensions


id: installation:installation-datasette-desktop
page: installation
ref: installation-datasette-desktop
title: Datasette Desktop for Mac
breadcrumbs: ["Installation", "Basic installation"]
references: [{"href": "https://datasette.io/desktop", "label": "Datasette Desktop"}]
content:
Datasette Desktop  is a packaged Mac application which bundles Datasette together with Python and allows you to install and run Datasette directly on your laptop. This is the best option for local installation if you are not comfortable using the command line.


id: installation:installation-homebrew
page: installation
ref: installation-homebrew
title: Using Homebrew
breadcrumbs: ["Installation", "Basic installation"]
references: [{"href": "https://brew.sh/", "label": "Homebrew"}]
content:
If you have a Mac and use  Homebrew , you can install Datasette by running this command in your terminal: 
                 brew install datasette 
                 This should install the latest version. You can confirm by running: 
                 datasette --version 
                 You can upgrade to the latest Homebrew packaged version using: 
                 brew upgrade datasette 
                 Once you have installed Datasette you can install plugins using the following: 
                 datasette install datasette-vega 
                 If the latest packaged release of Datasette has not yet been made available through Homebrew, you can upgrade your Homebrew installation in-place using: 
                 datasette install -U datasette


id: installation:installation-pip
page: installation
ref: installation-pip
title: Using pip
breadcrumbs: ["Installation", "Basic installation"]
content:
Datasette requires Python 3.7 or higher. The  Python.org Python For Beginners  page has instructions for getting started. 
                 You can install Datasette and its dependencies using  pip : 
                 pip install datasette 
                 You can now run Datasette like so: 
                 datasette

references:
[{"href": "https://www.python.org/about/gettingstarted/", "label": "Python.org Python For Beginners"}]


id: installation:installation-pipx
page: installation
ref: installation-pipx
title: Using pipx
breadcrumbs: ["Installation", "Advanced installation options"]
content:
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.

references:
[{"href": "https://pipxproject.github.io/pipx/", "label": "pipx"}, {"href": "https://brew.sh/", "label": "Homebrew"}]


id: installation:installing-plugins-using-pipx
page: installation
ref: installing-plugins-using-pipx
title: Installing plugins using pipx
breadcrumbs: ["Installation", "Advanced installation options", "Using pipx"]
references: []
content:
You can install additional datasette plugins with  pipx inject  like so: 
                     $ pipx inject datasette datasette-json-html
injected package datasette-json-html into venv datasette
done! ✨ 🌟 ✨

$ datasette plugins
[
    {
        "name": "datasette-json-html",
        "static": false,
        "templates": false,
        "version": "0.6"
    }
]


id: installation:upgrading-packages-using-pipx
page: installation
ref: upgrading-packages-using-pipx
title: Upgrading packages using pipx
breadcrumbs: ["Installation", "Advanced installation options", "Using pipx"]
references: []
content:
You can upgrade your pipx installation to the latest release of Datasette using  pipx upgrade datasette : 
                     $ pipx upgrade datasette
upgraded package datasette from 0.39 to 0.40 (location: /Users/simon/.local/pipx/venvs/datasette) 
                     To upgrade a plugin within the pipx environment use  pipx runpip datasette install -U name-of-plugin  - like this: 
                     % datasette plugins
[
    {
        "name": "datasette-vega",
        "static": true,
        "templates": false,
        "version": "0.6"
    }
]

$ pipx runpip datasette install -U datasette-vega
Collecting datasette-vega
Downloading datasette_vega-0.6.2-py3-none-any.whl (1.8 MB)
    |████████████████████████████████| 1.8 MB 2.0 MB/s
...
Installing collected packages: datasette-vega
Attempting uninstall: datasette-vega
    Found existing installation: datasette-vega 0.6
    Uninstalling datasette-vega-0.6:
    Successfully uninstalled datasette-vega-0.6
Successfully installed datasette-vega-0.6.2

$ datasette plugins
[
    {
        "name": "datasette-vega",
        "static": true,
        "templates": false,
        "version": "0.6.2"
    }
]


id: installation:installation-docker
page: installation
ref: installation-docker
title: Using Docker
breadcrumbs: ["Installation", "Advanced installation options"]
content:
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

references:
[{"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"}]


id: installation:loading-spatialite
page: installation
ref: loading-spatialite
title: Loading SpatiaLite
breadcrumbs: ["Installation", "Advanced installation options", "Using Docker"]
references: [{"href": "http://127.0.0.1:8001/-/versions", "label": "http://127.0.0.1:8001/-/versions"}]
content:
The  datasetteproject/datasette  image includes a recent version of the
                         SpatiaLite extension  for SQLite. To load and enable that
                        module, use the following command: 
                     docker run -p 8001:8001 -v `pwd`:/mnt \
    datasetteproject/datasette \
    datasette -p 8001 -h 0.0.0.0 /mnt/fixtures.db \
    --load-extension=spatialite 
                     You can confirm that SpatiaLite is successfully loaded by visiting
                         http://127.0.0.1:8001/-/versions


id: installation:installing-plugins
page: installation
ref: installing-plugins
title: Installing plugins
breadcrumbs: ["Installation", "Advanced installation options", "Using Docker"]
content:
If you want to install plugins into your local Datasette Docker image you can do
                        so using the following recipe. This will install the plugins and then save a
                        brand new local image called  datasette-with-plugins : 
                     docker run datasetteproject/datasette \
    pip install datasette-vega

docker commit $(docker ps -lq) datasette-with-plugins 
                     You can now run the new custom image like so: 
                     docker run -p 8001:8001 -v `pwd`:/mnt \
    datasette-with-plugins \
    datasette -p 8001 -h 0.0.0.0 /mnt/fixtures.db 
                     You can confirm that the plugins are installed by visiting
                         http://127.0.0.1:8001/-/plugins 
                     Some plugins such as  datasette-ripgrep  may need additional system packages. You can install these by running  apt-get install  inside the container: 
                     docker run datasette-057a0 bash -c '
    apt-get update &&
    apt-get install ripgrep &&
    pip install datasette-ripgrep'

docker commit $(docker ps -lq) datasette-with-ripgrep

references:
[{"href": "http://127.0.0.1:8001/-/plugins", "label": "http://127.0.0.1:8001/-/plugins"}, {"href": "https://datasette.io/plugins/datasette-ripgrep", "label": "datasette-ripgrep"}]


id: installation:installation-extensions
page: installation
ref: installation-extensions
title: A note about extensions
breadcrumbs: ["Installation"]
references: []
content:
SQLite supports extensions, such as  SpatiaLite  for geospatial operations. 
             These can be loaded using the  --load-extension  argument, like so: 
             datasette --load-extension=/usr/local/lib/mod_spatialite.dylib 
             Some Python installations do not include support for SQLite extensions. If this is the case you will see the following error when you attempt to load an extension: 
             
                 Your Python installation does not have the ability to load SQLite extensions. 
             
             In some cases you may see the following error message instead: 
             AttributeError: 'sqlite3.Connection' object has no attribute 'enable_load_extension' 
             On macOS the easiest fix for this is to install Datasette using Homebrew: 
             brew install datasette 
             Use  which datasette  to confirm that  datasette  will run that version. The output should look something like this: 
             /usr/local/opt/datasette/bin/datasette 
             If you get a different location here such as  /Library/Frameworks/Python.framework/Versions/3.10/bin/datasette  you can run the following command to cause  datasette  to execute the Homebrew version instead: 
             alias datasette=$(echo $(brew --prefix datasette)/bin/datasette) 
             You can undo this operation using: 
             unalias datasette 
             If you need to run SQLite with extension support for other Python code, you can do so by install Python itself using Homebrew: 
             brew install python 
             Then executing Python using: 
             /usr/local/opt/python@3/libexec/bin/python 
             A more convenient way to work with this version of Python may be to use it to create a virtual environment: 
             /usr/local/opt/python@3/libexec/bin/python -m venv datasette-venv 
             Then activate it like this: 
             source datasette-venv/bin/activate 
             Now running  python  and  pip  will work against a version of Python 3 that includes support for SQLite extensions: 
             pip install datasette
which datasette
datasette --version


