{"rowid": 1, "title": "Metadata", "content": "Data loves metadata. Any time you run Datasette you can optionally include a\n JSON file with metadata about your databases and tables. Datasette will then\n display that information in the web UI. \n Run Datasette like this: \n datasette database1.db database2.db --metadata metadata.json \n Your metadata.json file can look something like this: \n {\n \"title\": \"Custom title for your index page\",\n \"description\": \"Some description text can go here\",\n \"license\": \"ODbL\",\n \"license_url\": \"https://opendatacommons.org/licenses/odbl/\",\n \"source\": \"Original Data Source\",\n \"source_url\": \"http://example.com/\"\n} \n You can optionally use YAML instead of JSON, see Using YAML for metadata . \n The above metadata will be displayed on the index page of your Datasette-powered\n site. The source and license information will also be included in the footer of\n every page served by Datasette. \n Any special HTML characters in description will be escaped. If you want to\n include HTML in your description, you can use a description_html property\n instead.", "sections_fts": 1, "rank": null} {"rowid": 2, "title": "Per-database and per-table metadata", "content": "Metadata at the top level of the JSON will be shown on the index page and in the\n footer on every page of the site. The license and source is expected to apply to\n all of your data. \n You can also provide metadata at the per-database or per-table level, like this: \n {\n \"databases\": {\n \"database1\": {\n \"source\": \"Alternative source\",\n \"source_url\": \"http://example.com/\",\n \"tables\": {\n \"example_table\": {\n \"description_html\": \"Custom table description\",\n \"license\": \"CC BY 3.0 US\",\n \"license_url\": \"https://creativecommons.org/licenses/by/3.0/us/\"\n }\n }\n }\n }\n} \n Each of the top-level metadata fields can be used at the database and table level.", "sections_fts": 1, "rank": null} {"rowid": 3, "title": "Source, license and about", "content": "The three visible metadata fields you can apply to everything, specific databases or specific tables are source, license and about. All three are optional. \n source and source_url should be used to indicate where the underlying data came from. \n license and license_url should be used to indicate the license under which the data can be used. \n about and about_url can be used to link to further information about the project - an accompanying blog entry for example. \n For each of these you can provide just the *_url field and Datasette will treat that as the default link label text and display the URL directly on the page.", "sections_fts": 1, "rank": null} {"rowid": 4, "title": "Column descriptions", "content": "You can include descriptions for your columns by adding a \"columns\": {\"name-of-column\": \"description-of-column\"} block to your table metadata: \n {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"columns\": {\n \"column1\": \"Description of column 1\",\n \"column2\": \"Description of column 2\"\n }\n }\n }\n }\n }\n} \n These will be displayed at the top of the table page, and will also show in the cog menu for each column. \n You can see an example of how these look at latest.datasette.io/fixtures/roadside_attractions .", "sections_fts": 1, "rank": null} {"rowid": 5, "title": "Specifying units for a column", "content": "Datasette supports attaching units to a column, which will be used when displaying\n values from that column. SI prefixes will be used where appropriate. \n Column units are configured in the metadata like so: \n {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"units\": {\n \"column1\": \"metres\",\n \"column2\": \"Hz\"\n }\n }\n }\n }\n }\n} \n Units are interpreted using Pint , and you can see the full list of available units in\n Pint's unit registry . You can also add custom units to the metadata, which will be\n registered with Pint: \n {\n \"custom_units\": [\n \"decibel = [] = dB\"\n ]\n}", "sections_fts": 1, "rank": null} {"rowid": 6, "title": "Setting a default sort order", "content": "By default Datasette tables are sorted by primary key. You can over-ride this default for a specific table using the \"sort\" or \"sort_desc\" metadata properties: \n {\n \"databases\": {\n \"mydatabase\": {\n \"tables\": {\n \"example_table\": {\n \"sort\": \"created\"\n }\n }\n }\n }\n} \n Or use \"sort_desc\" to sort in descending order: \n {\n \"databases\": {\n \"mydatabase\": {\n \"tables\": {\n \"example_table\": {\n \"sort_desc\": \"created\"\n }\n }\n }\n }\n}", "sections_fts": 1, "rank": null} {"rowid": 7, "title": "Setting a custom page size", "content": "Datasette defaults to displaing 100 rows per page, for both tables and views. You can change this default page size on a per-table or per-view basis using the \"size\" key in metadata.json : \n {\n \"databases\": {\n \"mydatabase\": {\n \"tables\": {\n \"example_table\": {\n \"size\": 10\n }\n }\n }\n }\n} \n This size can still be over-ridden by passing e.g. ?_size=50 in the query string.", "sections_fts": 1, "rank": null} {"rowid": 8, "title": "Setting which columns can be used for sorting", "content": "Datasette allows any column to be used for sorting by default. If you need to\n control which columns are available for sorting you can do so using the optional\n sortable_columns key: \n {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"sortable_columns\": [\n \"height\",\n \"weight\"\n ]\n }\n }\n }\n }\n} \n This will restrict sorting of example_table to just the height and\n weight columns. \n You can also disable sorting entirely by setting \"sortable_columns\": [] \n You can use sortable_columns to enable specific sort orders for a view called name_of_view in the database my_database like so: \n {\n \"databases\": {\n \"my_database\": {\n \"tables\": {\n \"name_of_view\": {\n \"sortable_columns\": [\n \"clicks\",\n \"impressions\"\n ]\n }\n }\n }\n }\n}", "sections_fts": 1, "rank": null} {"rowid": 9, "title": "Specifying the label column for a table", "content": "Datasette's HTML interface attempts to display foreign key references as\n labelled hyperlinks. By default, it looks for referenced tables that only have\n two columns: a primary key column and one other. It assumes that the second\n column should be used as the link label. \n If your table has more than two columns you can specify which column should be\n used for the link label with the label_column property: \n {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"label_column\": \"title\"\n }\n }\n }\n }\n}", "sections_fts": 1, "rank": null} {"rowid": 10, "title": "Hiding tables", "content": "You can hide tables from the database listing view (in the same way that FTS and\n SpatiaLite tables are automatically hidden) using \"hidden\": true : \n {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"hidden\": true\n }\n }\n }\n }\n}", "sections_fts": 1, "rank": null} {"rowid": 11, "title": "Using YAML for metadata", "content": "Datasette accepts YAML as an alternative to JSON for your metadata configuration file. YAML is particularly useful for including multiline HTML and SQL strings. \n Here's an example of a metadata.yml file, re-using an example from Canned queries . \n title: Demonstrating Metadata from YAML\ndescription_html: |-\n

This description includes a long HTML string

\n \nlicense: ODbL\nlicense_url: https://opendatacommons.org/licenses/odbl/\ndatabases:\n fixtures:\n tables:\n no_primary_key:\n hidden: true\n queries:\n neighborhood_search:\n sql: |-\n select neighborhood, facet_cities.name, state\n from facetable join facet_cities on facetable.city_id = facet_cities.id\n where neighborhood like '%' || :text || '%' order by neighborhood;\n title: Search neighborhoods\n description_html: |-\n

This demonstrates basic LIKE search \n The metadata.yml file is passed to Datasette using the same --metadata option: \n datasette fixtures.db --metadata metadata.yml", "sections_fts": 1, "rank": null} {"rowid": 12, "title": "Custom pages and templates", "content": "Datasette provides a number of ways of customizing the way data is displayed.", "sections_fts": 1, "rank": null} {"rowid": 13, "title": "Custom CSS and JavaScript", "content": "When you launch Datasette, you can specify a custom metadata file like this: \n datasette mydb.db --metadata metadata.json \n Your metadata.json file can include links that look like this: \n {\n \"extra_css_urls\": [\n \"https://simonwillison.net/static/css/all.bf8cd891642c.css\"\n ],\n \"extra_js_urls\": [\n \"https://code.jquery.com/jquery-3.2.1.slim.min.js\"\n ]\n} \n The extra CSS and JavaScript files will be linked in the of every page: \n \n \n You can also specify a SRI (subresource integrity hash) for these assets: \n {\n \"extra_css_urls\": [\n {\n \"url\": \"https://simonwillison.net/static/css/all.bf8cd891642c.css\",\n \"sri\": \"sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI\"\n }\n ],\n \"extra_js_urls\": [\n {\n \"url\": \"https://code.jquery.com/jquery-3.2.1.slim.min.js\",\n \"sri\": \"sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=\"\n }\n ]\n} \n This will produce: \n \n \n Modern browsers will only execute the stylesheet or JavaScript if the SRI hash\n matches the content served. You can generate hashes using www.srihash.org \n Items in \"extra_js_urls\" can specify \"module\": true if they reference JavaScript that uses JavaScript modules . This configuration: \n {\n \"extra_js_urls\": [\n {\n \"url\": \"https://example.datasette.io/module.js\",\n \"module\": true\n }\n ]\n} \n Will produce this HTML: \n ", "sections_fts": 1, "rank": null} {"rowid": 14, "title": "CSS classes on the ", "content": "Every default template includes CSS classes in the body designed to support\n custom styling. \n The index template (the top level page at / ) gets this: \n \n The database template ( /dbname ) gets this: \n \n The custom SQL template ( /dbname?sql=... ) gets this: \n \n A canned query template ( /dbname/queryname ) gets this: \n \n The table template ( /dbname/tablename ) gets: \n \n The row template ( /dbname/tablename/rowid ) gets: \n \n The db-x and table-x classes use the database or table names themselves if\n they are valid CSS identifiers. If they aren't, we strip any invalid\n characters out and append a 6 character md5 digest of the original name, in\n order to ensure that multiple tables which resolve to the same stripped\n character version still have different CSS classes. \n Some examples: \n \"simple\" => \"simple\"\n\"MixedCase\" => \"MixedCase\"\n\"-no-leading-hyphens\" => \"no-leading-hyphens-65bea6\"\n\"_no-leading-underscores\" => \"no-leading-underscores-b921bc\"\n\"no spaces\" => \"no-spaces-7088d7\"\n\"-\" => \"336d5e\"\n\"no $ characters\" => \"no--characters-59e024\" \n and elements also get custom CSS classes reflecting the\n database column they are representing, for example: \n \n \n \n \n \n \n \n \n \n \n \n \n \n
idname
1SMITH
", "sections_fts": 1, "rank": null} {"rowid": 15, "title": "Serving static files", "content": "Datasette can serve static files for you, using the --static option.\n Consider the following directory structure: \n metadata.json\nstatic-files/styles.css\nstatic-files/app.js \n You can start Datasette using --static assets:static-files/ to serve those\n files from the /assets/ mount point: \n $ datasette -m metadata.json --static assets:static-files/ --memory \n The following URLs will now serve the content from those CSS and JS files: \n http://localhost:8001/assets/styles.css\nhttp://localhost:8001/assets/app.js \n You can reference those files from metadata.json like so: \n {\n \"extra_css_urls\": [\n \"/assets/styles.css\"\n ],\n \"extra_js_urls\": [\n \"/assets/app.js\"\n ]\n}", "sections_fts": 1, "rank": null} {"rowid": 16, "title": "Publishing static assets", "content": "The datasette publish command can be used to publish your static assets,\n using the same syntax as above: \n $ datasette publish cloudrun mydb.db --static assets:static-files/ \n This will upload the contents of the static-files/ directory as part of the\n deployment, and configure Datasette to correctly serve the assets from /assets/ .", "sections_fts": 1, "rank": null} {"rowid": 17, "title": "Custom templates", "content": "By default, Datasette uses default templates that ship with the package. \n You can over-ride these templates by specifying a custom --template-dir like\n this: \n datasette mydb.db --template-dir=mytemplates/ \n Datasette will now first look for templates in that directory, and fall back on\n the defaults if no matches are found. \n It is also possible to over-ride templates on a per-database, per-row or per-\n table basis. \n The lookup rules Datasette uses are as follows: \n Index page (/):\n index.html\n\nDatabase page (/mydatabase):\n database-mydatabase.html\n database.html\n\nCustom query page (/mydatabase?sql=...):\n query-mydatabase.html\n query.html\n\nCanned query page (/mydatabase/canned-query):\n query-mydatabase-canned-query.html\n query-mydatabase.html\n query.html\n\nTable page (/mydatabase/mytable):\n table-mydatabase-mytable.html\n table.html\n\nRow page (/mydatabase/mytable/id):\n row-mydatabase-mytable.html\n row.html\n\nTable of rows and columns include on table page:\n _table-table-mydatabase-mytable.html\n _table-mydatabase-mytable.html\n _table.html\n\nTable of rows and columns include on row page:\n _table-row-mydatabase-mytable.html\n _table-mydatabase-mytable.html\n _table.html \n If a table name has spaces or other unexpected characters in it, the template\n filename will follow the same rules as our custom CSS classes - for\n example, a table called \"Food Trucks\" will attempt to load the following\n templates: \n table-mydatabase-Food-Trucks-399138.html\ntable.html \n You can find out which templates were considered for a specific page by viewing\n source on that page and looking for an HTML comment at the bottom. The comment\n will look something like this: \n \n This example is from the canned query page for a query called \"tz\" in the\n database called \"mydb\". The asterisk shows which template was selected - so in\n this case, Datasette found a template file called query-mydb-tz.html and\n used that - but if that template had not been found, it would have tried for\n query-mydb.html or the default query.html . \n It is possible to extend the default templates using Jinja template\n inheritance. If you want to customize EVERY row template with some additional\n content you can do so by creating a row.html template like this: \n {% extends \"default:row.html\" %}\n\n{% block content %}\n

EXTRA HTML AT THE TOP OF THE CONTENT BLOCK

\n

This line renders the original block:

\n{{ super() }}\n{% endblock %} \n Note the default:row.html template name, which ensures Jinja will inherit\n from the default template. \n The _table.html template is included by both the row and the table pages,\n and a list of rows. The default _table.html template renders them as an\n HTML template and can be seen here . \n You can provide a custom template that applies to all of your databases and\n tables, or you can provide custom templates for specific tables using the\n template naming scheme described above. \n If you want to present your data in a format other than an HTML table, you\n can do so by looping through display_rows in your own _table.html \n template. You can use {{ row[\"column_name\"] }} to output the raw value\n of a specific column. \n If you want to output the rendered HTML version of a column, including any\n links to foreign keys, you can use {{ row.display(\"column_name\") }} . \n Here is an example of a custom _table.html template: \n {% for row in display_rows %}\n
\n

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

\n

{{ row[\"description\"] }}\n

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

\n
\n{% endfor %}", "sections_fts": 1, "rank": null} {"rowid": 18, "title": "Custom pages", "content": "You can add templated pages to your Datasette instance by creating HTML files in a pages directory within your templates directory. \n For example, to add a custom page that is served at http://localhost/about you would create a file in templates/pages/about.html , then start Datasette like this: \n $ datasette mydb.db --template-dir=templates/ \n You can nest directories within pages to create a nested structure. To create a http://localhost:8001/about/map page you would create templates/pages/about/map.html .", "sections_fts": 1, "rank": null} {"rowid": 19, "title": "Path parameters for pages", "content": "You can define custom pages that match multiple paths by creating files with {variable} definitions in their filenames. \n For example, to capture any request to a URL matching /about/* , you would create a template in the following location: \n templates/pages/about/{slug}.html \n A hit to /about/news would render that template and pass in a variable called slug with a value of \"news\" . \n If you use this mechanism don't forget to return a 404 if the referenced content could not be found. You can do this using {{ raise_404() }} described below. \n Templates defined using custom page routes work particularly well with the sql() template function from datasette-template-sql or the graphql() template function from datasette-graphql .", "sections_fts": 1, "rank": null} {"rowid": 20, "title": "Custom headers and status codes", "content": "Custom pages default to being served with a content-type of text/html; charset=utf-8 and a 200 status code. You can change these by calling a custom function from within your template. \n For example, to serve a custom page with a 418 I'm a teapot HTTP status code, create a file in pages/teapot.html containing the following: \n {{ custom_status(418) }}\n\nTeapot\n\nI'm a teapot\n\n \n To serve a custom HTTP header, add a custom_header(name, value) function call. For example: \n {{ custom_status(418) }}\n{{ custom_header(\"x-teapot\", \"I am\") }}\n\nTeapot\n\nI'm a teapot\n\n \n You can verify this is working using curl like this: \n $ curl -I 'http://127.0.0.1:8001/teapot'\nHTTP/1.1 418\ndate: Sun, 26 Apr 2020 18:38:30 GMT\nserver: uvicorn\nx-teapot: I am\ncontent-type: text/html; charset=utf-8", "sections_fts": 1, "rank": null} {"rowid": 21, "title": "Returning 404s", "content": "To indicate that content could not be found and display the default 404 page you can use the raise_404(message) function: \n {% if not rows %}\n {{ raise_404(\"Content not found\") }}\n{% endif %} \n If you call raise_404() the other content in your template will be ignored.", "sections_fts": 1, "rank": null} {"rowid": 22, "title": "Custom redirects", "content": "You can use the custom_redirect(location) function to redirect users to another page, for example in a file called pages/datasette.html : \n {{ custom_redirect(\"https://github.com/simonw/datasette\") }} \n Now requests to http://localhost:8001/datasette will result in a redirect. \n These redirects are served with a 302 Found status code by default. You can send a 301 Moved Permanently code by passing 301 as the second argument to the function: \n {{ custom_redirect(\"https://github.com/simonw/datasette\", 301) }}", "sections_fts": 1, "rank": null} {"rowid": 23, "title": "Custom error pages", "content": "Datasette returns an error page if an unexpected error occurs, access is forbidden or content cannot be found. \n You can customize the response returned for these errors by providing a custom error page template. \n Content not found errors use a 404.html template. Access denied errors use 403.html . Invalid input errors use 400.html . Unexpected errors of other kinds use 500.html . \n If a template for the specific error code is not found a template called error.html will be used instead. If you do not provide that template Datasette's default error.html template will be used. \n The error template will be passed the following context: \n \n \n status - integer \n \n The integer HTTP status code, e.g. 404, 500, 403, 400. \n \n \n \n error - string \n \n Details of the specific error, usually a full sentence. \n \n \n \n title - string or None \n \n A title for the page representing the class of error. This is often None for errors that do not provide a title separate from their error message.", "sections_fts": 1, "rank": null} {"rowid": 24, "title": "Changelog", "content": "", "sections_fts": 1, "rank": null} {"rowid": 25, "title": "0.62a0 (2022-05-02)", "content": "Datasette now runs some SQL queries in parallel. This has limited impact on performance, see this research issue for details. \n \n \n Datasette should now be compatible with Pyodide. ( #1733 ) \n \n \n datasette publish cloudrun has a new --timeout option which can be used to increase the time limit applied by the Google Cloud build environment. Thanks, Tim Sherratt. ( #1717 ) \n \n \n Spaces in database names are now encoded as + rather than ~20 . ( #1701 ) \n \n \n is now displayed as and is accompanied by tooltip showing \"2.3MB\". ( #1712 ) \n \n \n Don't show the facet option in the cog menu if faceting is not allowed. ( #1683 ) \n \n \n Code examples in the documentation are now all formatted using Black. ( #1718 ) \n \n \n Request.fake() method is now documented, see Request object .", "sections_fts": 1, "rank": null} {"rowid": 26, "title": "0.61.1 (2022-03-23)", "content": "Fixed a bug where databases with a different route from their name (as used by the datasette-hashed-urls plugin ) returned errors when executing custom SQL queries. ( #1682 )", "sections_fts": 1, "rank": null} {"rowid": 27, "title": "0.61 (2022-03-23)", "content": "In preparation for Datasette 1.0, this release includes two potentially backwards-incompatible changes. Hashed URL mode has been moved to a separate plugin, and the way Datasette generates URLs to databases and tables with special characters in their name such as / and . has changed. \n Datasette also now requires Python 3.7 or higher. \n \n \n URLs within Datasette now use a different encoding scheme for tables or databases that include \"special\" characters outside of the range of a-zA-Z0-9_- . This scheme is explained here: Tilde encoding . ( #1657 ) \n \n \n Removed hashed URL mode from Datasette. The new datasette-hashed-urls plugin can be used to achieve the same result, see datasette-hashed-urls for details. ( #1661 ) \n \n \n Databases can now have a custom path within the Datasette instance that is independent of the database name, using the db.route property. ( #1668 ) \n \n \n Datasette is now covered by a Code of Conduct . ( #1654 ) \n \n \n Python 3.6 is no longer supported. ( #1577 ) \n \n \n Tests now run against Python 3.11-dev. ( #1621 ) \n \n \n New datasette.ensure_permissions(actor, permissions) internal method for checking multiple permissions at once. ( #1675 ) \n \n \n New datasette.check_visibility(actor, action, resource=None) internal method for checking if a user can see a resource that would otherwise be invisible to unauthenticated users. ( #1678 ) \n \n \n Table and row HTML pages now include a element and return a Link: URL; rel=\"alternate\"; type=\"application/json+datasette\" HTTP header pointing to the JSON version of those pages. ( #1533 ) \n \n \n Access-Control-Expose-Headers: Link is now added to the CORS headers, allowing remote JavaScript to access that header. \n \n \n Canned queries are now shown at the top of the database page, directly below the SQL editor. Previously they were shown at the bottom, below the list of tables. ( #1612 ) \n \n \n Datasette now has a default favicon. ( #1603 ) \n \n \n sqlite_stat tables are now hidden by default. ( #1587 ) \n \n \n SpatiaLite tables data_licenses , KNN and KNN2 are now hidden by default. ( #1601 ) \n \n \n SQL query tracing mechanism now works for queries executed in asyncio sub-tasks, such as those created by asyncio.gather() . ( #1576 ) \n \n \n datasette.tracer mechanism is now documented. \n \n \n Common Datasette symbols can now be imported directly from the top-level datasette package, see Import shortcuts . Those symbols are Response , Forbidden , NotFound , hookimpl , actor_matches_allow . ( #957 ) \n \n \n /-/versions page now returns additional details for libraries used by SpatiaLite. ( #1607 ) \n \n \n Documentation now links to the Datasette Tutorials . \n \n \n Datasette will now also look for SpatiaLite in /opt/homebrew - thanks, Dan Peterson. ( #1649 ) \n \n \n Fixed bug where custom pages did not work on Windows. Thanks, Robert Christie. ( #1545 ) \n \n \n Fixed error caused when a table had a column named n . ( #1228 )", "sections_fts": 1, "rank": null} {"rowid": 28, "title": "0.60.2 (2022-02-07)", "content": "Fixed a bug where Datasette would open the same file twice with two different database names if you ran datasette file.db file.db . ( #1632 )", "sections_fts": 1, "rank": null} {"rowid": 29, "title": "0.60.1 (2022-01-20)", "content": "Fixed a bug where installation on Python 3.6 stopped working due to a change to an underlying dependency. This release can now be installed on Python 3.6, but is the last release of Datasette that will support anything less than Python 3.7. ( #1609 )", "sections_fts": 1, "rank": null} {"rowid": 30, "title": "0.60 (2022-01-13)", "content": "", "sections_fts": 1, "rank": null} {"rowid": 31, "title": "Plugins and internals", "content": "New plugin hook: filters_from_request(request, database, table, datasette) , which runs on the table page and can be used to support new custom query string parameters that modify the SQL query. ( #473 ) \n \n \n Added two additional methods for writing to the database: await db.execute_write_script(sql, block=True) and await db.execute_write_many(sql, params_seq, block=True) . ( #1570 ) \n \n \n The db.execute_write() internal method now defaults to blocking until the write operation has completed. Previously it defaulted to queuing the write and then continuing to run code while the write was in the queue. ( #1579 ) \n \n \n Database write connections now execute the prepare_connection(conn, database, datasette) plugin hook. ( #1564 ) \n \n \n The Datasette() constructor no longer requires the files= argument, and is now documented at Datasette class . ( #1563 ) \n \n \n The tracing feature now traces write queries, not just read queries. ( #1568 ) \n \n \n The query string variables exposed by request.args will now include blank strings for arguments such as foo in ?foo=&bar=1 rather than ignoring those parameters entirely. ( #1551 )", "sections_fts": 1, "rank": null} {"rowid": 32, "title": "Faceting", "content": "The number of unique values in a facet is now always displayed. Previously it was only displayed if the user specified ?_facet_size=max . ( #1556 ) \n \n \n Facets of type date or array can now be configured in metadata.json , see Facets in metadata.json . Thanks, David Larlet. ( #1552 ) \n \n \n New ?_nosuggest=1 parameter for table views, which disables facet suggestion. ( #1557 ) \n \n \n Fixed bug where ?_facet_array=tags&_facet=tags would only display one of the two selected facets. ( #625 )", "sections_fts": 1, "rank": null} {"rowid": 33, "title": "Other small fixes", "content": "Made several performance improvements to the database schema introspection code that runs when Datasette first starts up. ( #1555 ) \n \n \n Label columns detected for foreign keys are now case-insensitive, so Name or TITLE will be detected in the same way as name or title . ( #1544 ) \n \n \n Upgraded Pluggy dependency to 1.0. ( #1575 ) \n \n \n Now using Plausible analytics for the Datasette documentation. \n \n \n explain query plan is now allowed with varying amounts of whitespace in the query. ( #1588 ) \n \n \n New CLI reference page showing the output of --help for each of the datasette sub-commands. This lead to several small improvements to the help copy. ( #1594 ) \n \n \n Fixed bug where writable canned queries could not be used with custom templates. ( #1547 ) \n \n \n Improved fix for a bug where columns with a underscore prefix could result in unnecessary hidden form fields. ( #1527 )", "sections_fts": 1, "rank": null} {"rowid": 34, "title": "0.59.4 (2021-11-29)", "content": "Fixed bug where columns with a leading underscore could not be removed from the interactive filters list. ( #1527 ) \n \n \n Fixed bug where columns with a leading underscore were not correctly linked to by the \"Links from other tables\" interface on the row page. ( #1525 ) \n \n \n Upgraded dependencies aiofiles , black and janus .", "sections_fts": 1, "rank": null} {"rowid": 35, "title": "0.59.3 (2021-11-20)", "content": "Fixed numerous bugs when running Datasette behind a proxy with a prefix URL path using the base_url setting. A live demo of this mode is now available at datasette-apache-proxy-demo.datasette.io/prefix/ . ( #1519 , #838 ) \n \n \n ?column__arraycontains= and ?column__arraynotcontains= table parameters now also work against SQL views. ( #448 ) \n \n \n ?_facet_array=column no longer returns incorrect counts if columns contain the same value more than once.", "sections_fts": 1, "rank": null} {"rowid": 36, "title": "0.59.2 (2021-11-13)", "content": "Column names with a leading underscore now work correctly when used as a facet. ( #1506 ) \n \n \n Applying ?_nocol= to a column no longer removes that column from the filtering interface. ( #1503 ) \n \n \n Official Datasette Docker container now uses Debian Bullseye as the base image. ( #1497 ) \n \n \n Datasette is four years old today! Here's the original release announcement from 2017.", "sections_fts": 1, "rank": null} {"rowid": 37, "title": "0.59.1 (2021-10-24)", "content": "Fix compatibility with Python 3.10. ( #1482 ) \n \n \n Documentation on how to use Named parameters with integer and floating point values. ( #1496 )", "sections_fts": 1, "rank": null} {"rowid": 38, "title": "0.59 (2021-10-14)", "content": "Columns can now have associated metadata descriptions in metadata.json , see Column descriptions . ( #942 ) \n \n \n New register_commands() plugin hook allows plugins to register additional Datasette CLI commands, e.g. datasette mycommand file.db . ( #1449 ) \n \n \n Adding ?_facet_size=max to a table page now shows the number of unique values in each facet. ( #1423 ) \n \n \n Upgraded dependency httpx 0.20 - the undocumented allow_redirects= parameter to datasette.client is now follow_redirects= , and defaults to False where it previously defaulted to True . ( #1488 ) \n \n \n The --cors option now causes Datasette to return the Access-Control-Allow-Headers: Authorization header, in addition to Access-Control-Allow-Origin: * . ( #1467 ) \n \n \n Code that figures out which named parameters a SQL query takes in order to display form fields for them is no longer confused by strings that contain colon characters. ( #1421 ) \n \n \n Renamed --help-config option to --help-settings . ( #1431 ) \n \n \n datasette.databases property is now a documented API. ( #1443 ) \n \n \n The base.html template now wraps everything other than the