{"id": "plugin_hooks:plugin-register-output-renderer", "page": "plugin_hooks", "ref": "plugin-register-output-renderer", "title": "register_output_renderer(datasette)", "content": "datasette - Datasette class \n \n You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) \n \n \n \n Registers a new output renderer, to output data in a custom format. The hook function should return a dictionary, or a list of dictionaries, of the following shape: \n @hookimpl\ndef register_output_renderer(datasette):\n return {\n \"extension\": \"test\",\n \"render\": render_demo,\n \"can_render\": can_render_demo, # Optional\n } \n This will register render_demo to be called when paths with the extension .test (for example /database.test , /database/table.test , or /database/table/row.test ) are requested. \n render_demo is a Python function. It can be a regular function or an async def render_demo() awaitable function, depending on if it needs to make any asynchronous calls. \n can_render_demo is a Python function (or async def function) which accepts the same arguments as render_demo but just returns True or False . It lets Datasette know if the current SQL query can be represented by the plugin - and hence influence if a link to this output format is displayed in the user interface. If you omit the \"can_render\" key from the dictionary every query will be treated as being supported by the plugin. \n When a request is received, the \"render\" callback function is called with zero or more of the following arguments. Datasette will inspect your callback function and pass arguments that match its function signature. \n \n \n datasette - Datasette class \n \n For accessing plugin configuration and executing queries. \n \n \n \n columns - list of strings \n \n The names of the columns returned by this query. \n \n \n \n rows - list of sqlite3.Row objects \n \n The rows returned by the query. \n \n \n \n sql - string \n \n The SQL query that was executed. \n \n \n \n query_name - string or None \n \n If this was the execution of a canned query , the name of that query. \n \n \n \n database - string \n \n The name of the database. \n \n \n \n table - string or None \n \n The table or view, if one is being rendered. \n \n \n \n request - Request object \n \n The current HTTP request. \n \n \n \n error - string or None \n \n If an error occurred this string will contain the error message. \n \n \n \n truncated - bool or None \n \n If the query response was truncated - for example a SQL query returning more than 1,000 results where pagination is not available - this will be True . \n \n \n \n view_name - string \n \n The name of the current view being called. index , database , table , and row are the most important ones. \n \n \n \n The callback function can return None , if it is unable to render the data, or a Response class that will be returned to the caller. \n It can also return a dictionary with the following keys. This format is deprecated as-of Datasette 0.49 and will be removed by Datasette 1.0. \n \n \n body - string or bytes, optional \n \n The response body, default empty \n \n \n \n content_type - string, optional \n \n The Content-Type header, default text/plain \n \n \n \n status_code - integer, optional \n \n The HTTP status code, default 200 \n \n \n \n headers - dictionary, optional \n \n Extra HTTP headers to be returned in the response. \n \n \n \n An example of an output renderer callback function: \n def render_demo():\n return Response.text(\"Hello World\") \n Here is a more complex example: \n async def render_demo(datasette, columns, rows):\n db = datasette.get_database()\n result = await db.execute(\"select sqlite_version()\")\n first_row = \" | \".join(columns)\n lines = [first_row]\n lines.append(\"=\" * len(first_row))\n for row in rows:\n lines.append(\" | \".join(row))\n return Response(\n \"\\n\".join(lines),\n content_type=\"text/plain; charset=utf-8\",\n headers={\"x-sqlite-version\": result.first()[0]},\n ) \n And here is an example can_render function which returns True only if the query results contain the columns atom_id , atom_title and atom_updated : \n def can_render_demo(columns):\n return {\n \"atom_id\",\n \"atom_title\",\n \"atom_updated\",\n }.issubset(columns) \n Examples: datasette-atom , datasette-ics , datasette-geojson , datasette-copyable", "breadcrumbs": "[\"Plugin hooks\"]", "references": "[{\"href\": \"https://datasette.io/plugins/datasette-atom\", \"label\": \"datasette-atom\"}, {\"href\": \"https://datasette.io/plugins/datasette-ics\", \"label\": \"datasette-ics\"}, {\"href\": \"https://datasette.io/plugins/datasette-geojson\", \"label\": \"datasette-geojson\"}, {\"href\": \"https://datasette.io/plugins/datasette-copyable\", \"label\": \"datasette-copyable\"}]"} {"id": "plugin_hooks:plugin-register-permissions", "page": "plugin_hooks", "ref": "plugin-register-permissions", "title": "register_permissions(datasette)", "content": "If your plugin needs to register additional permissions unique to that plugin - upload-csvs for example - you can return a list of those permissions from this hook. \n from datasette import hookimpl, Permission\n\n\n@hookimpl\ndef register_permissions(datasette):\n return [\n Permission(\n name=\"upload-csvs\",\n abbr=None,\n description=\"Upload CSV files\",\n takes_database=True,\n takes_resource=False,\n default=False,\n )\n ] \n The fields of the Permission class are as follows: \n \n \n name - string \n \n The name of the permission, e.g. upload-csvs . This should be unique across all plugins that the user might have installed, so choose carefully. \n \n \n \n abbr - string or None \n \n An abbreviation of the permission, e.g. uc . This is optional - you can set it to None if you do not want to pick an abbreviation. Since this needs to be unique across all installed plugins it's best not to specify an abbreviation at all. If an abbreviation is provided it will be used when creating restricted signed API tokens. \n \n \n \n description - string or None \n \n A human-readable description of what the permission lets you do. Should make sense as the second part of a sentence that starts \"A user with this permission can ...\". \n \n \n \n takes_database - boolean \n \n True if this permission can be granted on a per-database basis, False if it is only valid at the overall Datasette instance level. \n \n \n \n takes_resource - boolean \n \n True if this permission can be granted on a per-resource basis. A resource is a database table, SQL view or canned query . \n \n \n \n default - boolean \n \n The default value for this permission if it is not explicitly granted to a user. True means the permission is granted by default, False means it is not. \n This should only be True if you want anonymous users to be able to take this action.", "breadcrumbs": "[\"Plugin hooks\"]", "references": "[]"} {"id": "plugin_hooks:plugin-register-routes", "page": "plugin_hooks", "ref": "plugin-register-routes", "title": "register_routes(datasette)", "content": "datasette - Datasette class \n \n You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) \n \n \n \n Register additional view functions to execute for specified URL routes. \n Return a list of (regex, view_function) pairs, something like this: \n from datasette import hookimpl, Response\nimport html\n\n\nasync def hello_from(request):\n name = request.url_vars[\"name\"]\n return Response.html(\n \"Hello from {}\".format(html.escape(name))\n )\n\n\n@hookimpl\ndef register_routes():\n return [(r\"^/hello-from/(?P.*)$\", hello_from)] \n The view functions can take a number of different optional arguments. The corresponding argument will be passed to your function depending on its named parameters - a form of dependency injection. \n The optional view function arguments are as follows: \n \n \n datasette - Datasette class \n \n You can use this to access plugin configuration options via datasette.plugin_config(your_plugin_name) , or to execute SQL queries. \n \n \n \n request - Request object \n \n The current HTTP request. \n \n \n \n scope - dictionary \n \n The incoming ASGI scope dictionary. \n \n \n \n send - function \n \n The ASGI send function. \n \n \n \n receive - function \n \n The ASGI receive function. \n \n \n \n The view function can be a regular function or an async def function, depending on if it needs to use any await APIs. \n The function can either return a Response class or it can return nothing and instead respond directly to the request using the ASGI send function (for advanced uses only). \n It can also raise the datasette.NotFound exception to return a 404 not found error, or the datasette.Forbidden exception for a 403 forbidden. \n See Designing URLs for your plugin for tips on designing the URL routes used by your plugin. \n Examples: datasette-auth-github , datasette-psutil", "breadcrumbs": "[\"Plugin hooks\"]", "references": "[{\"href\": \"https://datasette.io/plugins/datasette-auth-github\", \"label\": \"datasette-auth-github\"}, {\"href\": \"https://datasette.io/plugins/datasette-psutil\", \"label\": \"datasette-psutil\"}]"} {"id": "performance:http-caching", "page": "performance", "ref": "http-caching", "title": "HTTP caching", "content": "If your database is immutable and guaranteed not to change, you can gain major performance improvements from Datasette by enabling HTTP caching. \n This can work at two different levels. First, it can tell browsers to cache the results of queries and serve future requests from the browser cache. \n More significantly, it allows you to run Datasette behind a caching proxy such as Varnish or use a cache provided by a hosted service such as Fastly or Cloudflare . This can provide incredible speed-ups since a query only needs to be executed by Datasette the first time it is accessed - all subsequent hits can then be served by the cache. \n Using a caching proxy in this way could enable a Datasette-backed visualization to serve thousands of hits a second while running Datasette itself on extremely inexpensive hosting. \n Datasette's integration with HTTP caches can be enabled using a combination of configuration options and query string arguments. \n The default_cache_ttl setting sets the default HTTP cache TTL for all Datasette pages. This is 5 seconds unless you change it - you can set it to 0 if you wish to disable HTTP caching entirely. \n You can also change the cache timeout on a per-request basis using the ?_ttl=10 query string parameter. This can be useful when you are working with the Datasette JSON API - you may decide that a specific query can be cached for a longer time, or maybe you need to set ?_ttl=0 for some requests for example if you are running a SQL order by random() query.", "breadcrumbs": "[\"Performance and caching\"]", "references": "[{\"href\": \"https://varnish-cache.org/\", \"label\": \"Varnish\"}, {\"href\": \"https://www.fastly.com/\", \"label\": \"Fastly\"}, {\"href\": \"https://www.cloudflare.com/\", \"label\": \"Cloudflare\"}]"} {"id": "performance:performance", "page": "performance", "ref": "performance", "title": "Performance and caching", "content": "Datasette runs on top of SQLite, and SQLite has excellent performance. For small databases almost any query should return in just a few milliseconds, and larger databases (100s of MBs or even GBs of data) should perform extremely well provided your queries make sensible use of database indexes. \n That said, there are a number of tricks you can use to improve Datasette's performance.", "breadcrumbs": "[]", "references": "[]"} {"id": "performance:performance-hashed-urls", "page": "performance", "ref": "performance-hashed-urls", "title": "datasette-hashed-urls", "content": "If you open a database file in immutable mode using the -i option, you can be assured that the content of that database will not change for the lifetime of the Datasette server. \n The datasette-hashed-urls plugin implements an optimization where your database is served with part of the SHA-256 hash of the database contents baked into the URL. \n A database at /fixtures will instead be served at /fixtures-aa7318b , and a year-long cache expiry header will be returned with those pages. \n This will then be cached by both browsers and caching proxies such as Cloudflare or Fastly, providing a potentially significant performance boost. \n To install the plugin, run the following: \n datasette install datasette-hashed-urls \n \n Prior to Datasette 0.61 hashed URL mode was a core Datasette feature, enabled using the hash_urls setting. This implementation has now been removed in favor of the datasette-hashed-urls plugin. \n Prior to Datasette 0.28 hashed URL mode was the default behaviour for Datasette, since all database files were assumed to be immutable and unchanging. From 0.28 onwards the default has been to treat database files as mutable unless explicitly configured otherwise.", "breadcrumbs": "[\"Performance and caching\"]", "references": "[{\"href\": \"https://datasette.io/plugins/datasette-hashed-urls\", \"label\": \"datasette-hashed-urls plugin\"}]"} {"id": "performance:performance-immutable-mode", "page": "performance", "ref": "performance-immutable-mode", "title": "Immutable mode", "content": "If you can be certain that a SQLite database file will not be changed by another process you can tell Datasette to open that file in immutable mode . \n Doing so will disable all locking and change detection, which can result in improved query performance. \n This also enables further optimizations relating to HTTP caching, described below. \n To open a file in immutable mode pass it to the datasette command using the -i option: \n datasette -i data.db \n When you open a file in immutable mode like this Datasette will also calculate and cache the row counts for each table in that database when it first starts up, further improving performance.", "breadcrumbs": "[\"Performance and caching\"]", "references": "[]"} {"id": "performance:performance-inspect", "page": "performance", "ref": "performance-inspect", "title": "Using \"datasette inspect\"", "content": "Counting the rows in a table can be a very expensive operation on larger databases. In immutable mode Datasette performs this count only once and caches the results, but this can still cause server startup time to increase by several seconds or more. \n If you know that a database is never going to change you can precalculate the table row counts once and store then in a JSON file, then use that file when you later start the server. \n To create a JSON file containing the calculated row counts for a database, use the following: \n datasette inspect data.db --inspect-file=counts.json \n Then later you can start Datasette against the counts.json file and use it to skip the row counting step and speed up server startup: \n datasette -i data.db --inspect-file=counts.json \n You need to use the -i immutable mode against the database file here or the counts from the JSON file will be ignored. \n You will rarely need to use this optimization in every-day use, but several of the datasette publish commands described in Publishing data use this optimization for better performance when deploying a database file to a hosting provider.", "breadcrumbs": "[\"Performance and caching\"]", "references": "[]"} {"id": "pages:databaseview", "page": "pages", "ref": "databaseview", "title": "Database", "content": "Each database has a page listing the tables, views and canned queries available for that database. If the execute-sql permission is enabled (it's on by default) there will also be an interface for executing arbitrary SQL select queries against the data. \n Examples: \n \n \n fivethirtyeight.datasettes.com/fivethirtyeight \n \n \n global-power-plants.datasettes.com/global-power-plants \n \n \n The JSON version of this page provides programmatic access to the underlying data: \n \n \n fivethirtyeight.datasettes.com/fivethirtyeight.json \n \n \n global-power-plants.datasettes.com/global-power-plants.json", "breadcrumbs": "[\"Pages and API endpoints\"]", "references": "[{\"href\": \"https://fivethirtyeight.datasettes.com/fivethirtyeight\", \"label\": \"fivethirtyeight.datasettes.com/fivethirtyeight\"}, {\"href\": \"https://global-power-plants.datasettes.com/global-power-plants\", \"label\": \"global-power-plants.datasettes.com/global-power-plants\"}, {\"href\": \"https://fivethirtyeight.datasettes.com/fivethirtyeight.json\", \"label\": \"fivethirtyeight.datasettes.com/fivethirtyeight.json\"}, {\"href\": \"https://global-power-plants.datasettes.com/global-power-plants.json\", \"label\": \"global-power-plants.datasettes.com/global-power-plants.json\"}]"} {"id": "pages:databaseview-hidden", "page": "pages", "ref": "databaseview-hidden", "title": "Hidden tables", "content": "Some tables listed on the database page are treated as hidden. Hidden tables are not completely invisible - they can be accessed through the \"hidden tables\" link at the bottom of the page. They are hidden because they represent low-level implementation details which are generally not useful to end-users of Datasette. \n The following tables are hidden by default: \n \n \n Any table with a name that starts with an underscore - this is a Datasette convention to help plugins easily hide their own internal tables. \n \n \n Tables that have been configured as \"hidden\": true using Hiding tables . \n \n \n *_fts tables that implement SQLite full-text search indexes. \n \n \n Tables relating to the inner workings of the SpatiaLite SQLite extension. \n \n \n sqlite_stat tables used to store statistics used by the query optimizer.", "breadcrumbs": "[\"Pages and API endpoints\", \"Database\"]", "references": "[]"} {"id": "pages:indexview", "page": "pages", "ref": "indexview", "title": "Top-level index", "content": "The root page of any Datasette installation is an index page that lists all of the currently attached databases. Some examples: \n \n \n fivethirtyeight.datasettes.com \n \n \n global-power-plants.datasettes.com \n \n \n register-of-members-interests.datasettes.com \n \n \n Add /.json to the end of the URL for the JSON version of the underlying data: \n \n \n fivethirtyeight.datasettes.com/.json \n \n \n global-power-plants.datasettes.com/.json \n \n \n register-of-members-interests.datasettes.com/.json", "breadcrumbs": "[\"Pages and API endpoints\"]", "references": "[{\"href\": \"https://fivethirtyeight.datasettes.com/\", \"label\": \"fivethirtyeight.datasettes.com\"}, {\"href\": \"https://global-power-plants.datasettes.com/\", \"label\": \"global-power-plants.datasettes.com\"}, {\"href\": \"https://register-of-members-interests.datasettes.com/\", \"label\": \"register-of-members-interests.datasettes.com\"}, {\"href\": \"https://fivethirtyeight.datasettes.com/.json\", \"label\": \"fivethirtyeight.datasettes.com/.json\"}, {\"href\": \"https://global-power-plants.datasettes.com/.json\", \"label\": \"global-power-plants.datasettes.com/.json\"}, {\"href\": \"https://register-of-members-interests.datasettes.com/.json\", \"label\": \"register-of-members-interests.datasettes.com/.json\"}]"} {"id": "pages:pages", "page": "pages", "ref": "pages", "title": "Pages and API endpoints", "content": "The Datasette web application offers a number of different pages that can be accessed to explore the data in question, each of which is accompanied by an equivalent JSON API.", "breadcrumbs": "[]", "references": "[]"} {"id": "pages:rowview", "page": "pages", "ref": "rowview", "title": "Row", "content": "Every row in every Datasette table has its own URL. This means individual records can be linked to directly. \n Table cells with extremely long text contents are truncated on the table view according to the truncate_cells_html setting. If a cell has been truncated the full length version of that cell will be available on the row page. \n Rows which are the targets of foreign key references from other tables will show a link to a filtered search for all records that reference that row. Here's an example from the Registers of Members Interests database: \n ../people/uk~2Eorg~2Epublicwhip~2Fperson~2F10001 \n Note that this URL includes the encoded primary key of the record. \n Here's that same page as JSON: \n ../people/uk~2Eorg~2Epublicwhip~2Fperson~2F10001.json", "breadcrumbs": "[\"Pages and API endpoints\"]", "references": "[{\"href\": \"https://register-of-members-interests.datasettes.com/regmem/people/uk~2Eorg~2Epublicwhip~2Fperson~2F10001\", \"label\": \"../people/uk~2Eorg~2Epublicwhip~2Fperson~2F10001\"}, {\"href\": \"https://register-of-members-interests.datasettes.com/regmem/people/uk~2Eorg~2Epublicwhip~2Fperson~2F10001.json\", \"label\": \"../people/uk~2Eorg~2Epublicwhip~2Fperson~2F10001.json\"}]"} {"id": "pages:tableview", "page": "pages", "ref": "tableview", "title": "Table", "content": "The table page is the heart of Datasette: it allows users to interactively explore the contents of a database table, including sorting, filtering, Full-text search and applying Facets . \n The HTML interface is worth spending some time exploring. As with other pages, you can return the JSON data by appending .json to the URL path, before any ? query string arguments. \n The query string arguments are described in more detail here: Table arguments \n You can also use the table page to interactively construct a SQL query - by applying different filters and a sort order for example - and then click the \"View and edit SQL\" link to see the SQL query that was used for the page and edit and re-submit it. \n Some examples: \n \n \n ../items lists all of the line-items registered by UK MPs as potential conflicts of interest. It demonstrates Datasette's support for Full-text search . \n \n \n ../antiquities-act%2Factions_under_antiquities_act is an interface for exploring the \"actions under the antiquities act\" data table published by FiveThirtyEight. \n \n \n ../global-power-plants?country_long=United+Kingdom&primary_fuel=Gas is a filtered table page showing every Gas power plant in the United Kingdom. It includes some default facets (configured using its metadata.json ) and uses the datasette-cluster-map plugin to show a map of the results.", "breadcrumbs": "[\"Pages and API endpoints\"]", "references": "[{\"href\": \"https://register-of-members-interests.datasettes.com/regmem/items\", \"label\": \"../items\"}, {\"href\": \"https://fivethirtyeight.datasettes.com/fivethirtyeight/antiquities-act%2Factions_under_antiquities_act\", \"label\": \"../antiquities-act%2Factions_under_antiquities_act\"}, {\"href\": \"https://global-power-plants.datasettes.com/global-power-plants/global-power-plants?_facet=primary_fuel&_facet=owner&_facet=country_long&country_long__exact=United+Kingdom&primary_fuel=Gas\", \"label\": \"../global-power-plants?country_long=United+Kingdom&primary_fuel=Gas\"}, {\"href\": \"https://global-power-plants.datasettes.com/-/metadata\", \"label\": \"its metadata.json\"}, {\"href\": \"https://github.com/simonw/datasette-cluster-map\", \"label\": \"datasette-cluster-map\"}]"} {"id": "metadata:database-level-metadata", "page": "metadata", "ref": "database-level-metadata", "title": "Database-level metadata", "content": "\"Database-level\" metadata refers to fields that can be specified for each database in a Datasette instance. These attributes should be listed under a database inside the \"databases\" field. \n The following are the full list of allowed database-level metadata fields: \n \n \n source \n \n \n source_url \n \n \n license \n \n \n license_url \n \n \n about \n \n \n about_url", "breadcrumbs": "[\"Metadata\", \"Metadata reference\"]", "references": "[]"} {"id": "metadata:id1", "page": "metadata", "ref": "id1", "title": "Metadata", "content": "Data loves metadata. Any time you run Datasette you can optionally include a\n YAML or 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.yaml \n Your metadata.yaml file can look something like this: \n [[[cog\nfrom metadata_doc import metadata_example\nmetadata_example(cog, {\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 ]]] \n [[[end]]] \n Choosing YAML over JSON adds support for multi-line strings and comments. \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.", "breadcrumbs": "[]", "references": "[]"} {"id": "metadata:id2", "page": "metadata", "ref": "id2", "title": "Metadata reference", "content": "A full reference of every supported option in a metadata.json or metadata.yaml file.", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:label-columns", "page": "metadata", "ref": "label-columns", "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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"label_column\": \"title\"\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]]", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:metadata-column-descriptions", "page": "metadata", "ref": "metadata-column-descriptions", "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 [[[cog\nmetadata_example(cog, {\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 ]]] \n [[[end]]] \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 .", "breadcrumbs": "[\"Metadata\"]", "references": "[{\"href\": \"https://latest.datasette.io/fixtures/roadside_attractions\", \"label\": \"latest.datasette.io/fixtures/roadside_attractions\"}]"} {"id": "metadata:metadata-default-sort", "page": "metadata", "ref": "metadata-default-sort", "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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"mydatabase\": {\n \"tables\": {\n \"example_table\": {\n \"sort\": \"created\"\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]] \n Or use \"sort_desc\" to sort in descending order: \n [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"mydatabase\": {\n \"tables\": {\n \"example_table\": {\n \"sort_desc\": \"created\"\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]]", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:metadata-hiding-tables", "page": "metadata", "ref": "metadata-hiding-tables", "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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"hidden\": True\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]]", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:metadata-page-size", "page": "metadata", "ref": "metadata-page-size", "title": "Setting a custom page size", "content": "Datasette defaults to displaying 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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"mydatabase\": {\n \"tables\": {\n \"example_table\": {\n \"size\": 10\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]] \n This size can still be over-ridden by passing e.g. ?_size=50 in the query string.", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:metadata-sortable-columns", "page": "metadata", "ref": "metadata-sortable-columns", "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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"sortable_columns\": [\n \"height\",\n \"weight\"\n ]\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]] \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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"my_database\": {\n \"tables\": {\n \"name_of_view\": {\n \"sortable_columns\": [\n \"clicks\",\n \"impressions\"\n ]\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]]", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:metadata-source-license-about", "page": "metadata", "ref": "metadata-source-license-about", "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.", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:per-database-and-per-table-metadata", "page": "metadata", "ref": "per-database-and-per-table-metadata", "title": "Per-database and per-table metadata", "content": "Metadata at the top level of the file 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 [[[cog\nmetadata_example(cog, {\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 ]]] \n [[[end]]] \n Each of the top-level metadata fields can be used at the database and table level.", "breadcrumbs": "[\"Metadata\"]", "references": "[]"} {"id": "metadata:specifying-units-for-a-column", "page": "metadata", "ref": "specifying-units-for-a-column", "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 [[[cog\nmetadata_example(cog, {\n \"databases\": {\n \"database1\": {\n \"tables\": {\n \"example_table\": {\n \"units\": {\n \"column1\": \"metres\",\n \"column2\": \"Hz\"\n }\n }\n }\n }\n }\n}) \n ]]] \n [[[end]]] \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 [[[cog\nmetadata_example(cog, {\n \"custom_units\": [\n \"decibel = [] = dB\"\n ]\n}) \n ]]] \n [[[end]]]", "breadcrumbs": "[\"Metadata\"]", "references": "[{\"href\": \"https://pint.readthedocs.io/\", \"label\": \"Pint\"}, {\"href\": \"https://github.com/hgrecco/pint/blob/master/pint/default_en.txt\", \"label\": \"unit registry\"}, {\"href\": \"http://pint.readthedocs.io/en/latest/defining.html\", \"label\": \"custom units\"}]"} {"id": "metadata:table-level-metadata", "page": "metadata", "ref": "table-level-metadata", "title": "Table-level metadata", "content": "\"Table-level\" metadata refers to fields that can be specified for each table in a Datasette instance. These attributes should be listed under a specific table using the \"tables\" field. \n The following are the full list of allowed table-level metadata fields: \n \n \n source \n \n \n source_url \n \n \n license \n \n \n license_url \n \n \n about \n \n \n about_url \n \n \n hidden \n \n \n sort/sort_desc \n \n \n size \n \n \n sortable_columns \n \n \n label_column \n \n \n facets \n \n \n fts_table \n \n \n fts_pk \n \n \n searchmode \n \n \n columns", "breadcrumbs": "[\"Metadata\", \"Metadata reference\"]", "references": "[]"} {"id": "metadata:top-level-metadata", "page": "metadata", "ref": "top-level-metadata", "title": "Top-level metadata", "content": "\"Top-level\" metadata refers to fields that can be specified at the root level of a metadata file. These attributes are meant to describe the entire Datasette instance. \n The following are the full list of allowed top-level metadata fields: \n \n \n title \n \n \n description \n \n \n description_html \n \n \n license \n \n \n license_url \n \n \n source \n \n \n source_url", "breadcrumbs": "[\"Metadata\", \"Metadata reference\"]", "references": "[]"} {"id": "json_api:column-filter-arguments", "page": "json_api", "ref": "column-filter-arguments", "title": "Column filter arguments", "content": "You can filter the data returned by the table based on column values using a query string argument. \n \n \n ?column__exact=value or ?_column=value \n \n Returns rows where the specified column exactly matches the value. \n \n \n \n ?column__not=value \n \n Returns rows where the column does not match the value. \n \n \n \n ?column__contains=value \n \n Rows where the string column contains the specified value ( column like \"%value%\" in SQL). \n \n \n \n ?column__notcontains=value \n \n Rows where the string column does not contain the specified value ( column not like \"%value%\" in SQL). \n \n \n \n ?column__endswith=value \n \n Rows where the string column ends with the specified value ( column like \"%value\" in SQL). \n \n \n \n ?column__startswith=value \n \n Rows where the string column starts with the specified value ( column like \"value%\" in SQL). \n \n \n \n ?column__gt=value \n \n Rows which are greater than the specified value. \n \n \n \n ?column__gte=value \n \n Rows which are greater than or equal to the specified value. \n \n \n \n ?column__lt=value \n \n Rows which are less than the specified value. \n \n \n \n ?column__lte=value \n \n Rows which are less than or equal to the specified value. \n \n \n \n ?column__like=value \n \n Match rows with a LIKE clause, case insensitive and with % as the wildcard character. \n \n \n \n ?column__notlike=value \n \n Match rows that do not match the provided LIKE clause. \n \n \n \n ?column__glob=value \n \n Similar to LIKE but uses Unix wildcard syntax and is case sensitive. \n \n \n \n ?column__in=value1,value2,value3 \n \n Rows where column matches any of the provided values. \n You can use a comma separated string, or you can use a JSON array. \n The JSON array option is useful if one of your matching values itself contains a comma: \n ?column__in=[\"value\",\"value,with,commas\"] \n \n \n \n ?column__notin=value1,value2,value3 \n \n Rows where column does not match any of the provided values. The inverse of __in= . Also supports JSON arrays. \n \n \n \n ?column__arraycontains=value \n \n Works against columns that contain JSON arrays - matches if any of the values in that array match the provided value. \n This is only available if the json1 SQLite extension is enabled. \n \n \n \n ?column__arraynotcontains=value \n \n Works against columns that contain JSON arrays - matches if none of the values in that array match the provided value. \n This is only available if the json1 SQLite extension is enabled. \n \n \n \n ?column__date=value \n \n Column is a datestamp occurring on the specified YYYY-MM-DD date, e.g. 2018-01-02 . \n \n \n \n ?column__isnull=1 \n \n Matches rows where the column is null. \n \n \n \n ?column__notnull=1 \n \n Matches rows where the column is not null. \n \n \n \n ?column__isblank=1 \n \n Matches rows where the column is blank, meaning null or the empty string. \n \n \n \n ?column__notblank=1 \n \n Matches rows where the column is not blank.", "breadcrumbs": "[\"JSON API\", \"Table arguments\"]", "references": "[]"} {"id": "json_api:expand-foreign-keys", "page": "json_api", "ref": "expand-foreign-keys", "title": "Expanding foreign key references", "content": "Datasette can detect foreign key relationships and resolve those references into\n labels. The HTML interface does this by default for every detected foreign key\n column - you can turn that off using ?_labels=off . \n You can request foreign keys be expanded in JSON using the _labels=on or\n _label=COLUMN special query string parameters. Here's what an expanded row\n looks like: \n [\n {\n \"rowid\": 1,\n \"TreeID\": 141565,\n \"qLegalStatus\": {\n \"value\": 1,\n \"label\": \"Permitted Site\"\n },\n \"qSpecies\": {\n \"value\": 1,\n \"label\": \"Myoporum laetum :: Myoporum\"\n },\n \"qAddress\": \"501X Baker St\",\n \"SiteOrder\": 1\n }\n] \n The column in the foreign key table that is used for the label can be specified\n in metadata.json - see Specifying the label column for a table .", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:id1", "page": "json_api", "ref": "id1", "title": "JSON API", "content": "Datasette provides a JSON API for your SQLite databases. Anything you can do\n through the Datasette user interface can also be accessed as JSON via the API. \n To access the API for a page, either click on the .json link on that page or\n edit the URL and add a .json extension to it.", "breadcrumbs": "[]", "references": "[]"} {"id": "json_api:id2", "page": "json_api", "ref": "id2", "title": "Table arguments", "content": "The Datasette table view takes a number of special query string arguments.", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:json-api-cors", "page": "json_api", "ref": "json-api-cors", "title": "Enabling CORS", "content": "If you start Datasette with the --cors option, each JSON endpoint will be\n served with the following additional HTTP headers: \n [[[cog\nfrom datasette.utils import add_cors_headers\nimport textwrap\nheaders = {}\nadd_cors_headers(headers)\noutput = \"\\n\".join(\"{}: {}\".format(k, v) for k, v in headers.items())\ncog.out(\"\\n::\\n\\n\")\ncog.out(textwrap.indent(output, ' '))\ncog.out(\"\\n\\n\") \n ]]] \n Access-Control-Allow-Origin: *\nAccess-Control-Allow-Headers: Authorization, Content-Type\nAccess-Control-Expose-Headers: Link\nAccess-Control-Allow-Methods: GET, POST, HEAD, OPTIONS\nAccess-Control-Max-Age: 3600 \n [[[end]]] \n This allows JavaScript running on any domain to make cross-origin\n requests to interact with the Datasette API. \n If you start Datasette without the --cors option only JavaScript running on\n the same domain as Datasette will be able to access the API. \n Here's how to serve data.db with CORS enabled: \n datasette data.db --cors", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:json-api-default", "page": "json_api", "ref": "json-api-default", "title": "Default representation", "content": "The default JSON representation of data from a SQLite table or custom query\n looks like this: \n {\n \"ok\": true,\n \"rows\": [\n {\n \"id\": 3,\n \"name\": \"Detroit\"\n },\n {\n \"id\": 2,\n \"name\": \"Los Angeles\"\n },\n {\n \"id\": 4,\n \"name\": \"Memnonia\"\n },\n {\n \"id\": 1,\n \"name\": \"San Francisco\"\n }\n ],\n \"truncated\": false\n} \n \"ok\" is always true if an error did not occur. \n The \"rows\" key is a list of objects, each one representing a row. \n The \"truncated\" key lets you know if the query was truncated. This can happen if a SQL query returns more than 1,000 results (or the max_returned_rows setting). \n For table pages, an additional key \"next\" may be present. This indicates that the next page in the pagination set can be retrieved using ?_next=VALUE .", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:json-api-discover-alternate", "page": "json_api", "ref": "json-api-discover-alternate", "title": "Discovering the JSON for a page", "content": "Most of the HTML pages served by Datasette provide a mechanism for discovering their JSON equivalents using the HTML link mechanism. \n You can find this near the top of the source code of those pages, looking like this: \n \n The JSON URL is also made available in a Link HTTP header for the page: \n Link: https://latest.datasette.io/fixtures/sortable.json; rel=\"alternate\"; type=\"application/json+datasette\"", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:json-api-pagination", "page": "json_api", "ref": "json-api-pagination", "title": "Pagination", "content": "The default JSON representation includes a \"next_url\" key which can be used to access the next page of results. If that key is null or missing then it means you have reached the final page of results. \n Other representations include pagination information in the link HTTP header. That header will look something like this: \n link: ; rel=\"next\" \n Here is an example Python function built using requests that returns a list of all of the paginated items from one of these API endpoints: \n def paginate(url):\n items = []\n while url:\n response = requests.get(url)\n try:\n url = response.links.get(\"next\").get(\"url\")\n except AttributeError:\n url = None\n items.extend(response.json())\n return items", "breadcrumbs": "[\"JSON API\"]", "references": "[{\"href\": \"https://requests.readthedocs.io/\", \"label\": \"requests\"}]"} {"id": "json_api:json-api-shapes", "page": "json_api", "ref": "json-api-shapes", "title": "Different shapes", "content": "The _shape parameter can be used to access alternative formats for the\n rows key which may be more convenient for your application. There are three\n options: \n \n \n ?_shape=objects - \"rows\" is a list of JSON key/value objects - the default \n \n \n ?_shape=arrays - \"rows\" is a list of lists, where the order of values in each list matches the order of the columns \n \n \n ?_shape=array - a JSON array of objects - effectively just the \"rows\" key from the default representation \n \n \n ?_shape=array&_nl=on - a newline-separated list of JSON objects \n \n \n ?_shape=arrayfirst - a flat JSON array containing just the first value from each row \n \n \n ?_shape=object - a JSON object keyed using the primary keys of the rows \n \n \n _shape=arrays looks like this: \n {\n \"ok\": true,\n \"next\": null,\n \"rows\": [\n [3, \"Detroit\"],\n [2, \"Los Angeles\"],\n [4, \"Memnonia\"],\n [1, \"San Francisco\"]\n ]\n} \n _shape=array looks like this: \n [\n {\n \"id\": 3,\n \"name\": \"Detroit\"\n },\n {\n \"id\": 2,\n \"name\": \"Los Angeles\"\n },\n {\n \"id\": 4,\n \"name\": \"Memnonia\"\n },\n {\n \"id\": 1,\n \"name\": \"San Francisco\"\n }\n] \n _shape=array&_nl=on looks like this: \n {\"id\": 1, \"value\": \"Myoporum laetum :: Myoporum\"}\n{\"id\": 2, \"value\": \"Metrosideros excelsa :: New Zealand Xmas Tree\"}\n{\"id\": 3, \"value\": \"Pinus radiata :: Monterey Pine\"} \n _shape=arrayfirst looks like this: \n [1, 2, 3] \n _shape=object looks like this: \n {\n \"1\": {\n \"id\": 1,\n \"value\": \"Myoporum laetum :: Myoporum\"\n },\n \"2\": {\n \"id\": 2,\n \"value\": \"Metrosideros excelsa :: New Zealand Xmas Tree\"\n },\n \"3\": {\n \"id\": 3,\n \"value\": \"Pinus radiata :: Monterey Pine\"\n }\n] \n The object shape is only available for queries against tables - custom SQL\n queries and views do not have an obvious primary key so cannot be returned using\n this format. \n The object keys are always strings. If your table has a compound primary\n key, the object keys will be a comma-separated string.", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:json-api-special", "page": "json_api", "ref": "json-api-special", "title": "Special JSON arguments", "content": "Every Datasette endpoint that can return JSON also accepts the following\n query string arguments: \n \n \n ?_shape=SHAPE \n \n The shape of the JSON to return, documented above. \n \n \n \n ?_nl=on \n \n When used with ?_shape=array produces newline-delimited JSON objects. \n \n \n \n ?_json=COLUMN1&_json=COLUMN2 \n \n If any of your SQLite columns contain JSON values, you can use one or more\n _json= parameters to request that those columns be returned as regular\n JSON. Without this argument those columns will be returned as JSON objects\n that have been double-encoded into a JSON string value. \n Compare this query without the argument to this query using the argument \n \n \n \n ?_json_infinity=on \n \n If your data contains infinity or -infinity values, Datasette will replace\n them with None when returning them as JSON. If you pass _json_infinity=1 \n Datasette will instead return them as Infinity or -Infinity which is\n invalid JSON but can be processed by some custom JSON parsers. \n \n \n \n ?_timelimit=MS \n \n Sets a custom time limit for the query in ms. You can use this for optimistic\n queries where you would like Datasette to give up if the query takes too\n long, for example if you want to implement autocomplete search but only if\n it can be executed in less than 10ms. \n \n \n \n ?_ttl=SECONDS \n \n For how many seconds should this response be cached by HTTP proxies? Use\n ?_ttl=0 to disable HTTP caching entirely for this request. \n \n \n \n ?_trace=1 \n \n Turns on tracing for this page: SQL queries executed during the request will\n be gathered and included in the response, either in a new \"_traces\" key\n for JSON responses or at the bottom of the page if the response is in HTML. \n The structure of the data returned here should be considered highly unstable\n and very likely to change. \n Only available if the trace_debug setting is enabled.", "breadcrumbs": "[\"JSON API\"]", "references": "[{\"href\": \"https://fivethirtyeight.datasettes.com/fivethirtyeight.json?sql=select+%27{%22this+is%22%3A+%22a+json+object%22}%27+as+d&_shape=array\", \"label\": \"this query without the argument\"}, {\"href\": \"https://fivethirtyeight.datasettes.com/fivethirtyeight.json?sql=select+%27{%22this+is%22%3A+%22a+json+object%22}%27+as+d&_shape=array&_json=d\", \"label\": \"this query using the argument\"}]"} {"id": "json_api:json-api-table-arguments", "page": "json_api", "ref": "json-api-table-arguments", "title": "Special table arguments", "content": "?_col=COLUMN1&_col=COLUMN2 \n \n List specific columns to display. These will be shown along with any primary keys. \n \n \n \n ?_nocol=COLUMN1&_nocol=COLUMN2 \n \n List specific columns to hide - any column not listed will be displayed. Primary keys cannot be hidden. \n \n \n \n ?_labels=on/off \n \n Expand foreign key references for every possible column. See below. \n \n \n \n ?_label=COLUMN1&_label=COLUMN2 \n \n Expand foreign key references for one or more specified columns. \n \n \n \n ?_size=1000 or ?_size=max \n \n Sets a custom page size. This cannot exceed the max_returned_rows limit\n passed to datasette serve . Use max to get max_returned_rows . \n \n \n \n ?_sort=COLUMN \n \n Sorts the results by the specified column. \n \n \n \n ?_sort_desc=COLUMN \n \n Sorts the results by the specified column in descending order. \n \n \n \n ?_search=keywords \n \n For SQLite tables that have been configured for\n full-text search executes a search\n with the provided keywords. \n \n \n \n ?_search_COLUMN=keywords \n \n Like _search= but allows you to specify the column to be searched, as\n opposed to searching all columns that have been indexed by FTS. \n \n \n \n ?_searchmode=raw \n \n With this option, queries passed to ?_search= or ?_search_COLUMN= will\n not have special characters escaped. This means you can make use of the full\n set of advanced SQLite FTS syntax ,\n though this could potentially result in errors if the wrong syntax is used. \n \n \n \n ?_where=SQL-fragment \n \n If the execute-sql permission is enabled, this parameter\n can be used to pass one or more additional SQL fragments to be used in the\n WHERE clause of the SQL used to query the table. \n This is particularly useful if you are building a JavaScript application\n that needs to do something creative but still wants the other conveniences\n provided by the table view (such as faceting) and hence would like not to\n have to construct a completely custom SQL query. \n Some examples: \n \n \n facetable?_where=_neighborhood like \"%c%\"&_where=_city_id=3 \n \n \n facetable?_where=_city_id in (select id from facet_cities where name != \"Detroit\") \n \n \n \n \n \n ?_through={json} \n \n This can be used to filter rows via a join against another table. \n The JSON parameter must include three keys: table , column and value . \n table must be a table that the current table is related to via a foreign key relationship. \n column must be a column in that other table. \n value is the value that you want to match against. \n For example, to filter roadside_attractions to just show the attractions that have a characteristic of \"museum\", you would construct this JSON: \n {\n \"table\": \"roadside_attraction_characteristics\",\n \"column\": \"characteristic_id\",\n \"value\": \"1\"\n} \n As a URL, that looks like this: \n ?_through={%22table%22:%22roadside_attraction_characteristics%22,%22column%22:%22characteristic_id%22,%22value%22:%221%22} \n Here's an example . \n \n \n \n ?_next=TOKEN \n \n Pagination by continuation token - pass the token that was returned in the\n \"next\" property by the previous page. \n \n \n \n ?_facet=column \n \n Facet by column. Can be applied multiple times, see Facets . Only works on the default JSON output, not on any of the custom shapes. \n \n \n \n ?_facet_size=100 \n \n Increase the number of facet results returned for each facet. Use ?_facet_size=max for the maximum available size, determined by max_returned_rows . \n \n \n \n ?_nofacet=1 \n \n Disable all facets and facet suggestions for this page, including any defined by Facets in metadata . \n \n \n \n ?_nosuggest=1 \n \n Disable facet suggestions for this page. \n \n \n \n ?_nocount=1 \n \n Disable the select count(*) query used on this page - a count of None will be returned instead.", "breadcrumbs": "[\"JSON API\", \"Table arguments\"]", "references": "[{\"href\": \"https://www.sqlite.org/fts3.html\", \"label\": \"full-text search\"}, {\"href\": \"https://www.sqlite.org/fts5.html#full_text_query_syntax\", \"label\": \"advanced SQLite FTS syntax\"}, {\"href\": \"https://latest.datasette.io/fixtures/facetable?_where=_neighborhood%20like%20%22%c%%22&_where=_city_id=3\", \"label\": \"facetable?_where=_neighborhood like \\\"%c%\\\"&_where=_city_id=3\"}, {\"href\": \"https://latest.datasette.io/fixtures/facetable?_where=_city_id%20in%20(select%20id%20from%20facet_cities%20where%20name%20!=%20%22Detroit%22)\", \"label\": \"facetable?_where=_city_id in (select id from facet_cities where name != \\\"Detroit\\\")\"}, {\"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\"}]"} {"id": "json_api:json-api-write", "page": "json_api", "ref": "json-api-write", "title": "The JSON write API", "content": "Datasette provides a write API for JSON data. This is a POST-only API that requires an authenticated API token, see API Tokens . The token will need to have the specified Permissions .", "breadcrumbs": "[\"JSON API\"]", "references": "[]"} {"id": "json_api:rowdeleteview", "page": "json_api", "ref": "rowdeleteview", "title": "Deleting a row", "content": "To delete a row, make a POST to ////-/delete . This requires the delete-row permission. \n POST //
//-/delete\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n here is the tilde-encoded primary key value of the row to delete - or a comma-separated list of primary key values if the table has a composite primary key. \n If successful, this will return a 200 status code and a {\"ok\": true} response body. \n Any errors will return {\"errors\": [\"... descriptive message ...\"], \"ok\": false} , and a 400 status code for a bad input or a 403 status code for an authentication or permission error.", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "json_api:rowupdateview", "page": "json_api", "ref": "rowupdateview", "title": "Updating a row", "content": "To update a row, make a POST to //
//-/update . This requires the update-row permission. \n POST //
//-/update\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n {\n \"update\": {\n \"text_column\": \"New text string\",\n \"integer_column\": 3,\n \"float_column\": 3.14\n }\n} \n here is the tilde-encoded primary key value of the row to update - or a comma-separated list of primary key values if the table has a composite primary key. \n You only need to pass the columns you want to update. Any other columns will be left unchanged. \n If successful, this will return a 200 status code and a {\"ok\": true} response body. \n Add \"return\": true to the request body to return the updated row: \n {\n \"update\": {\n \"title\": \"New title\"\n },\n \"return\": true\n} \n The returned JSON will look like this: \n {\n \"ok\": true,\n \"row\": {\n \"id\": 1,\n \"title\": \"New title\",\n \"other_column\": \"Will be present here too\"\n }\n} \n Any errors will return {\"errors\": [\"... descriptive message ...\"], \"ok\": false} , and a 400 status code for a bad input or a 403 status code for an authentication or permission error. \n Pass \"alter: true to automatically add any missing columns to the table. This requires the alter-table permission.", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "json_api:tablecreateview", "page": "json_api", "ref": "tablecreateview", "title": "Creating a table", "content": "To create a table, make a POST to //-/create . This requires the create-table permission. \n POST //-/create\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n {\n \"table\": \"name_of_new_table\",\n \"columns\": [\n {\n \"name\": \"id\",\n \"type\": \"integer\"\n },\n {\n \"name\": \"title\",\n \"type\": \"text\"\n }\n ],\n \"pk\": \"id\"\n} \n The JSON here describes the table that will be created: \n \n \n table is the name of the table to create. This field is required. \n \n \n columns is a list of columns to create. Each column is a dictionary with name and type keys. \n \n \n name is the name of the column. This is required. \n \n \n type is the type of the column. This is optional - if not provided, text will be assumed. The valid types are text , integer , float and blob . \n \n \n \n \n pk is the primary key for the table. This is optional - if not provided, Datasette will create a SQLite table with a hidden rowid column. \n If the primary key is an integer column, it will be configured to automatically increment for each new record. \n If you set this to id without including an id column in the list of columns , Datasette will create an auto-incrementing integer ID column for you. \n \n \n pks can be used instead of pk to create a compound primary key. It should be a JSON list of column names to use in that primary key. \n \n \n ignore can be set to true to ignore existing rows by primary key if the table already exists. \n \n \n replace can be set to true to replace existing rows by primary key if the table already exists. This requires the update-row permission. \n \n \n alter can be set to true if you want to automatically add any missing columns to the table. This requires the alter-table permission. \n \n \n If the table is successfully created this will return a 201 status code and the following response: \n {\n \"ok\": true,\n \"database\": \"data\",\n \"table\": \"name_of_new_table\",\n \"table_url\": \"http://127.0.0.1:8001/data/name_of_new_table\",\n \"table_api_url\": \"http://127.0.0.1:8001/data/name_of_new_table.json\",\n \"schema\": \"CREATE TABLE [name_of_new_table] (\\n [id] INTEGER PRIMARY KEY,\\n [title] TEXT\\n)\"\n}", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "json_api:tablecreateview-example", "page": "json_api", "ref": "tablecreateview-example", "title": "Creating a table from example data", "content": "Instead of specifying columns directly you can instead pass a single example row or a list of rows .\n Datasette will create a table with a schema that matches those rows and insert them for you: \n POST //-/create\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n {\n \"table\": \"creatures\",\n \"rows\": [\n {\n \"id\": 1,\n \"name\": \"Tarantula\"\n },\n {\n \"id\": 2,\n \"name\": \"K\u0101k\u0101p\u014d\"\n }\n ],\n \"pk\": \"id\"\n} \n Doing this requires both the create-table and insert-row permissions. \n The 201 response here will be similar to the columns form, but will also include the number of rows that were inserted as row_count : \n {\n \"ok\": true,\n \"database\": \"data\",\n \"table\": \"creatures\",\n \"table_url\": \"http://127.0.0.1:8001/data/creatures\",\n \"table_api_url\": \"http://127.0.0.1:8001/data/creatures.json\",\n \"schema\": \"CREATE TABLE [creatures] (\\n [id] INTEGER PRIMARY KEY,\\n [name] TEXT\\n)\",\n \"row_count\": 2\n} \n You can call the create endpoint multiple times for the same table provided you are specifying the table using the rows or row option. New rows will be inserted into the table each time. This means you can use this API if you are unsure if the relevant table has been created yet. \n If you pass a row to the create endpoint with a primary key that already exists you will get an error that looks like this: \n {\n \"ok\": false,\n \"errors\": [\n \"UNIQUE constraint failed: creatures.id\"\n ]\n} \n You can avoid this error by passing the same \"ignore\": true or \"replace\": true options to the create endpoint as you can to the insert endpoint . \n To use the \"replace\": true option you will also need the update-row permission. \n Pass \"alter\": true to automatically add any missing columns to the existing table that are present in the rows you are submitting. This requires the alter-table permission.", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "json_api:tabledropview", "page": "json_api", "ref": "tabledropview", "title": "Dropping tables", "content": "To drop a table, make a POST to //
/-/drop . This requires the drop-table permission. \n POST //
/-/drop\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n Without a POST body this will return a status 200 with a note about how many rows will be deleted: \n {\n \"ok\": true,\n \"database\": \"\",\n \"table\": \"
\",\n \"row_count\": 5,\n \"message\": \"Pass \\\"confirm\\\": true to confirm\"\n} \n If you pass the following POST body: \n {\n \"confirm\": true\n} \n Then the table will be dropped and a status 200 response of {\"ok\": true} will be returned. \n Any errors will return {\"errors\": [\"... descriptive message ...\"], \"ok\": false} , and a 400 status code for a bad input or a 403 status code for an authentication or permission error.", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "json_api:tableinsertview", "page": "json_api", "ref": "tableinsertview", "title": "Inserting rows", "content": "This requires the insert-row permission. \n A single row can be inserted using the \"row\" key: \n POST //
/-/insert\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n {\n \"row\": {\n \"column1\": \"value1\",\n \"column2\": \"value2\"\n }\n} \n If successful, this will return a 201 status code and the newly inserted row, for example: \n {\n \"rows\": [\n {\n \"id\": 1,\n \"column1\": \"value1\",\n \"column2\": \"value2\"\n }\n ]\n} \n To insert multiple rows at a time, use the same API method but send a list of dictionaries as the \"rows\" key: \n POST //
/-/insert\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n {\n \"rows\": [\n {\n \"column1\": \"value1\",\n \"column2\": \"value2\"\n },\n {\n \"column1\": \"value3\",\n \"column2\": \"value4\"\n }\n ]\n} \n If successful, this will return a 201 status code and a {\"ok\": true} response body. \n The maximum number rows that can be submitted at once defaults to 100, but this can be changed using the max_insert_rows setting. \n To return the newly inserted rows, add the \"return\": true key to the request body: \n {\n \"rows\": [\n {\n \"column1\": \"value1\",\n \"column2\": \"value2\"\n },\n {\n \"column1\": \"value3\",\n \"column2\": \"value4\"\n }\n ],\n \"return\": true\n} \n This will return the same \"rows\" key as the single row example above. There is a small performance penalty for using this option. \n If any of your rows have a primary key that is already in use, you will get an error and none of the rows will be inserted: \n {\n \"ok\": false,\n \"errors\": [\n \"UNIQUE constraint failed: new_table.id\"\n ]\n} \n Pass \"ignore\": true to ignore these errors and insert the other rows: \n {\n \"rows\": [\n {\n \"id\": 1,\n \"column1\": \"value1\",\n \"column2\": \"value2\"\n },\n {\n \"id\": 2,\n \"column1\": \"value3\",\n \"column2\": \"value4\"\n }\n ],\n \"ignore\": true\n} \n Or you can pass \"replace\": true to replace any rows with conflicting primary keys with the new values. This requires the update-row permission. \n Pass \"alter: true to automatically add any missing columns to the table. This requires the alter-table permission.", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "json_api:tableupsertview", "page": "json_api", "ref": "tableupsertview", "title": "Upserting rows", "content": "An upsert is an insert or update operation. If a row with a matching primary key already exists it will be updated - otherwise a new row will be inserted. \n The upsert API is mostly the same shape as the insert API . It requires both the insert-row and update-row permissions. \n POST //
/-/upsert\nContent-Type: application/json\nAuthorization: Bearer dstok_ \n {\n \"rows\": [\n {\n \"id\": 1,\n \"title\": \"Updated title for 1\",\n \"description\": \"Updated description for 1\"\n },\n {\n \"id\": 2,\n \"description\": \"Updated description for 2\",\n },\n {\n \"id\": 3,\n \"title\": \"Item 3\",\n \"description\": \"Description for 3\"\n }\n ]\n} \n Imagine a table with a primary key of id and which already has rows with id values of 1 and 2 . \n The above example will: \n \n \n Update the row with id of 1 to set both title and description to the new values \n \n \n Update the row with id of 2 to set title to the new value - description will be left unchanged \n \n \n Insert a new row with id of 3 and both title and description set to the new values \n \n \n Similar to /-/insert , a row key with an object can be used instead of a rows array to upsert a single row. \n If successful, this will return a 200 status code and a {\"ok\": true} response body. \n Add \"return\": true to the request body to return full copies of the affected rows after they have been inserted or updated: \n {\n \"rows\": [\n {\n \"id\": 1,\n \"title\": \"Updated title for 1\",\n \"description\": \"Updated description for 1\"\n },\n {\n \"id\": 2,\n \"description\": \"Updated description for 2\",\n },\n {\n \"id\": 3,\n \"title\": \"Item 3\",\n \"description\": \"Description for 3\"\n }\n ],\n \"return\": true\n} \n This will return the following: \n {\n \"ok\": true,\n \"rows\": [\n {\n \"id\": 1,\n \"title\": \"Updated title for 1\",\n \"description\": \"Updated description for 1\"\n },\n {\n \"id\": 2,\n \"title\": \"Item 2\",\n \"description\": \"Updated description for 2\"\n },\n {\n \"id\": 3,\n \"title\": \"Item 3\",\n \"description\": \"Description for 3\"\n }\n ]\n} \n When using upsert you must provide the primary key column (or columns if the table has a compound primary key) for every row, or you will get a 400 error: \n {\n \"ok\": false,\n \"errors\": [\n \"Row 0 is missing primary key column(s): \\\"id\\\"\"\n ]\n} \n If your table does not have an explicit primary key you should pass the SQLite rowid key instead. \n Pass \"alter: true to automatically add any missing columns to the table. This requires the alter-table permission.", "breadcrumbs": "[\"JSON API\", \"The JSON write API\"]", "references": "[]"} {"id": "javascript_plugins:id1", "page": "javascript_plugins", "ref": "id1", "title": "JavaScript plugins", "content": "Datasette can run custom JavaScript in several different ways: \n \n \n Datasette plugins written in Python can use the extra_js_urls() or extra_body_script() plugin hooks to inject JavaScript into a page \n \n \n Datasette instances with custom templates can include additional JavaScript in those templates \n \n \n The extra_js_urls key in datasette.yaml can be used to include extra JavaScript \n \n \n There are no limitations on what this JavaScript can do. It is executed directly by the browser, so it can manipulate the DOM, fetch additional data and do anything else that JavaScript is capable of. \n \n Custom JavaScript has security implications, especially for authenticated Datasette instances where the JavaScript might run in the context of the authenticated user. It's important to carefully review any JavaScript you run in your Datasette instance.", "breadcrumbs": "[]", "references": "[]"} {"id": "javascript_plugins:id2", "page": "javascript_plugins", "ref": "id2", "title": "JavaScript plugin objects", "content": "JavaScript plugins are blocks of code that can be registered with Datasette using the registerPlugin() method on the datasetteManager object. \n The implementation object passed to this method should include a version key defining the plugin version, and one or more of the following named functions providing the implementation of the plugin:", "breadcrumbs": "[\"JavaScript plugins\"]", "references": "[]"} {"id": "javascript_plugins:javascript-datasette-init", "page": "javascript_plugins", "ref": "javascript-datasette-init", "title": "The datasette_init event", "content": "Datasette emits a custom event called datasette_init when the page is loaded. This event is dispatched on the document object, and includes a detail object with a reference to the datasetteManager object. \n Your JavaScript code can listen out for this event using document.addEventListener() like this: \n document.addEventListener(\"datasette_init\", function (evt) {\n const manager = evt.detail;\n console.log(\"Datasette version:\", manager.VERSION);\n});", "breadcrumbs": "[\"JavaScript plugins\"]", "references": "[]"} {"id": "javascript_plugins:javascript-datasette-manager", "page": "javascript_plugins", "ref": "javascript-datasette-manager", "title": "datasetteManager", "content": "The datasetteManager object \n \n \n VERSION - string \n \n The version of Datasette \n \n \n \n plugins - Map() \n \n A Map of currently loaded plugin names to plugin implementations \n \n \n \n registerPlugin(name, implementation) \n \n Call this to register a plugin, passing its name and implementation \n \n \n \n selectors - object \n \n An object providing named aliases to useful CSS selectors, listed below", "breadcrumbs": "[\"JavaScript plugins\"]", "references": "[]"} {"id": "javascript_plugins:javascript-datasette-manager-selectors", "page": "javascript_plugins", "ref": "javascript-datasette-manager-selectors", "title": "Selectors", "content": "These are available on the selectors property of the datasetteManager object. \n const DOM_SELECTORS = {\n /** Should have one match */\n jsonExportLink: \".export-links a[href*=json]\",\n\n /** Event listeners that go outside of the main table, e.g. existing scroll listener */\n tableWrapper: \".table-wrapper\",\n table: \"table.rows-and-columns\",\n aboveTablePanel: \".above-table-panel\",\n\n // These could have multiple matches\n /** Used for selecting table headers. Use makeColumnActions if you want to add menu items. */\n tableHeaders: `table.rows-and-columns th`,\n\n /** Used to add \"where\" clauses to query using direct manipulation */\n filterRows: \".filter-row\",\n /** Used to show top available enum values for a column (\"facets\") */\n facetResults: \".facet-results [data-column]\",\n};", "breadcrumbs": "[\"JavaScript plugins\"]", "references": "[]"} {"id": "javascript_plugins:javascript-plugins-makeabovetablepanelconfigs", "page": "javascript_plugins", "ref": "javascript-plugins-makeabovetablepanelconfigs", "title": "makeAboveTablePanelConfigs()", "content": "This method should return a JavaScript array of objects defining additional panels to be added to the top of the table page. Each object should have the following: \n \n \n id - string \n \n A unique string ID for the panel, for example map-panel \n \n \n \n label - string \n \n A human-readable label for the panel \n \n \n \n render(node) - function \n \n A function that will be called with a DOM node to render the panel into \n \n \n \n This example shows how a plugin might define a single panel: \n document.addEventListener('datasette_init', function(ev) {\n ev.detail.registerPlugin('panel-plugin', {\n version: 0.1,\n makeAboveTablePanelConfigs: () => {\n return [\n {\n id: 'first-panel',\n label: 'First panel',\n render: node => {\n node.innerHTML = '

My custom panel

This is a custom panel that I added using a JavaScript plugin

';\n }\n }\n ]\n }\n });\n}); \n When a page with a table loads, all registered plugins that implement makeAboveTablePanelConfigs() will be called and panels they return will be added to the top of the table page.", "breadcrumbs": "[\"JavaScript plugins\", \"JavaScript plugin objects\"]", "references": "[]"} {"id": "javascript_plugins:javascript-plugins-makecolumnactions", "page": "javascript_plugins", "ref": "javascript-plugins-makecolumnactions", "title": "makeColumnActions(columnDetails)", "content": "This method, if present, will be called when Datasette is rendering the cog action menu icons that appear at the top of the table view. By default these include options like \"Sort ascending/descending\" and \"Facet by this\", but plugins can return additional actions to be included in this menu. \n The method will be called with a columnDetails object with the following keys: \n \n \n columnName - string \n \n The name of the column \n \n \n \n columnNotNull - boolean \n \n True if the column is defined as NOT NULL \n \n \n \n columnType - string \n \n The SQLite data type of the column \n \n \n \n isPk - boolean \n \n True if the column is part of the primary key \n \n \n \n It should return a JavaScript array of objects each with a label and onClick property: \n \n \n label - string \n \n The human-readable label for the action \n \n \n \n onClick(evt) - function \n \n A function that will be called when the action is clicked \n \n \n \n The evt object passed to the onClick is the standard browser event object that triggered the click. \n This example plugin adds two menu items - one to copy the column name to the clipboard and another that displays the column metadata in an alert() window: \n document.addEventListener('datasette_init', function(ev) {\n ev.detail.registerPlugin('column-name-plugin', {\n version: 0.1,\n makeColumnActions: (columnDetails) => {\n return [\n {\n label: 'Copy column to clipboard',\n onClick: async (evt) => {\n await navigator.clipboard.writeText(columnDetails.columnName)\n }\n },\n {\n label: 'Alert column metadata',\n onClick: () => alert(JSON.stringify(columnDetails, null, 2))\n }\n ];\n }\n });\n});", "breadcrumbs": "[\"JavaScript plugins\", \"JavaScript plugin objects\"]", "references": "[]"} {"id": "introspection:id1", "page": "introspection", "ref": "id1", "title": "Introspection", "content": "Datasette includes some pages and JSON API endpoints for introspecting the current instance. These can be used to understand some of the internals of Datasette and to see how a particular instance has been configured. \n Each of these pages can be viewed in your browser. Add .json to the URL to get back the contents as JSON.", "breadcrumbs": "[]", "references": "[]"} {"id": "introspection:jsondataview-actor", "page": "introspection", "ref": "jsondataview-actor", "title": "/-/actor", "content": "Shows the currently authenticated actor. Useful for debugging Datasette authentication plugins. \n {\n \"actor\": {\n \"id\": 1,\n \"username\": \"some-user\"\n }\n}", "breadcrumbs": "[\"Introspection\"]", "references": "[]"} {"id": "introspection:jsondataview-config", "page": "introspection", "ref": "jsondataview-config", "title": "/-/config", "content": "Shows the configuration for this instance of Datasette. This is generally the contents of the datasette.yaml or datasette.json file, which can include plugin configuration as well. Config example : \n {\n \"settings\": {\n \"template_debug\": true,\n \"trace_debug\": true,\n \"force_https_urls\": true\n }\n} \n Any keys that include the one of the following substrings in their names will be returned as redacted *** output, to help avoid accidentally leaking private configuration information: secret , key , password , token , hash , dsn .", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://latest.datasette.io/-/config\", \"label\": \"Config example\"}]"} {"id": "introspection:jsondataview-databases", "page": "introspection", "ref": "jsondataview-databases", "title": "/-/databases", "content": "Shows currently attached databases. Databases example : \n [\n {\n \"hash\": null,\n \"is_memory\": false,\n \"is_mutable\": true,\n \"name\": \"fixtures\",\n \"path\": \"fixtures.db\",\n \"size\": 225280\n }\n]", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://latest.datasette.io/-/databases\", \"label\": \"Databases example\"}]"} {"id": "introspection:jsondataview-metadata", "page": "introspection", "ref": "jsondataview-metadata", "title": "/-/metadata", "content": "Shows the contents of the metadata.json file that was passed to datasette serve , if any. Metadata example : \n {\n \"license\": \"CC Attribution 4.0 License\",\n \"license_url\": \"http://creativecommons.org/licenses/by/4.0/\",\n \"source\": \"fivethirtyeight/data on GitHub\",\n \"source_url\": \"https://github.com/fivethirtyeight/data\",\n \"title\": \"Five Thirty Eight\",\n \"databases\": {\n\n }\n}", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://fivethirtyeight.datasettes.com/-/metadata\", \"label\": \"Metadata example\"}]"} {"id": "introspection:jsondataview-plugins", "page": "introspection", "ref": "jsondataview-plugins", "title": "/-/plugins", "content": "Shows a list of currently installed plugins and their versions. Plugins example : \n [\n {\n \"name\": \"datasette_cluster_map\",\n \"static\": true,\n \"templates\": false,\n \"version\": \"0.10\",\n \"hooks\": [\"extra_css_urls\", \"extra_js_urls\", \"extra_body_script\"]\n }\n] \n Add ?all=1 to include details of the default plugins baked into Datasette.", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://san-francisco.datasettes.com/-/plugins\", \"label\": \"Plugins example\"}]"} {"id": "introspection:jsondataview-settings", "page": "introspection", "ref": "jsondataview-settings", "title": "/-/settings", "content": "Shows the Settings for this instance of Datasette. Settings example : \n {\n \"default_facet_size\": 30,\n \"default_page_size\": 100,\n \"facet_suggest_time_limit_ms\": 50,\n \"facet_time_limit_ms\": 1000,\n \"max_returned_rows\": 1000,\n \"sql_time_limit_ms\": 1000\n}", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://fivethirtyeight.datasettes.com/-/settings\", \"label\": \"Settings example\"}]"} {"id": "introspection:jsondataview-threads", "page": "introspection", "ref": "jsondataview-threads", "title": "/-/threads", "content": "Shows details of threads and asyncio tasks. Threads example : \n {\n \"num_threads\": 2,\n \"threads\": [\n {\n \"daemon\": false,\n \"ident\": 4759197120,\n \"name\": \"MainThread\"\n },\n {\n \"daemon\": true,\n \"ident\": 123145319682048,\n \"name\": \"Thread-1\"\n },\n ],\n \"num_tasks\": 3,\n \"tasks\": [\n \" cb=[set.discard()]>\",\n \" wait_for=()]> cb=[run_until_complete..()]>\",\n \" wait_for=()]>>\"\n ]\n}", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://latest.datasette.io/-/threads\", \"label\": \"Threads example\"}]"} {"id": "introspection:jsondataview-versions", "page": "introspection", "ref": "jsondataview-versions", "title": "/-/versions", "content": "Shows the version of Datasette, Python and SQLite. Versions example : \n {\n \"datasette\": {\n \"version\": \"0.60\"\n },\n \"python\": {\n \"full\": \"3.8.12 (default, Dec 21 2021, 10:45:09) \\n[GCC 10.2.1 20210110]\",\n \"version\": \"3.8.12\"\n },\n \"sqlite\": {\n \"extensions\": {\n \"json1\": null\n },\n \"fts_versions\": [\n \"FTS5\",\n \"FTS4\",\n \"FTS3\"\n ],\n \"compile_options\": [\n \"COMPILER=gcc-6.3.0 20170516\",\n \"ENABLE_FTS3\",\n \"ENABLE_FTS4\",\n \"ENABLE_FTS5\",\n \"ENABLE_JSON1\",\n \"ENABLE_RTREE\",\n \"THREADSAFE=1\"\n ],\n \"version\": \"3.37.0\"\n }\n}", "breadcrumbs": "[\"Introspection\"]", "references": "[{\"href\": \"https://latest.datasette.io/-/versions\", \"label\": \"Versions example\"}]"} {"id": "introspection:messagesdebugview", "page": "introspection", "ref": "messagesdebugview", "title": "/-/messages", "content": "The debug tool at /-/messages can be used to set flash messages to try out that feature. See .add_message(request, message, type=datasette.INFO) for details of this feature.", "breadcrumbs": "[\"Introspection\"]", "references": "[]"} {"id": "internals:database-close", "page": "internals", "ref": "database-close", "title": "db.close()", "content": "Closes all of the open connections to file-backed databases. This is mainly intended to be used by large test suites, to avoid hitting limits on the number of open files.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-constructor", "page": "internals", "ref": "database-constructor", "title": "Database(ds, path=None, is_mutable=True, is_memory=False, memory_name=None)", "content": "The Database() constructor can be used by plugins, in conjunction with .add_database(db, name=None, route=None) , to create and register new databases. \n The arguments are as follows: \n \n \n ds - Datasette class (required) \n \n The Datasette instance you are attaching this database to. \n \n \n \n path - string \n \n Path to a SQLite database file on disk. \n \n \n \n is_mutable - boolean \n \n Set this to False to cause Datasette to open the file in immutable mode. \n \n \n \n is_memory - boolean \n \n Use this to create non-shared memory connections. \n \n \n \n memory_name - string or None \n \n Use this to create a named in-memory database. Unlike regular memory databases these can be accessed by multiple threads and will persist an changes made to them for the lifetime of the Datasette server process. \n \n \n \n The first argument is the datasette instance you are attaching to, the second is a path= , then is_mutable and is_memory are both optional arguments.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-execute", "page": "internals", "ref": "database-execute", "title": "await db.execute(sql, ...)", "content": "Executes a SQL query against the database and returns the resulting rows (see Results ). \n \n \n sql - string (required) \n \n The SQL query to execute. This can include ? or :named parameters. \n \n \n \n params - list or dict \n \n A list or dictionary of values to use for the parameters. List for ? , dictionary for :named . \n \n \n \n truncate - boolean \n \n Should the rows returned by the query be truncated at the maximum page size? Defaults to True , set this to False to disable truncation. \n \n \n \n custom_time_limit - integer ms \n \n A custom time limit for this query. This can be set to a lower value than the Datasette configured default. If a query takes longer than this it will be terminated early and raise a dataette.database.QueryInterrupted exception. \n \n \n \n page_size - integer \n \n Set a custom page size for truncation, over-riding the configured Datasette default. \n \n \n \n log_sql_errors - boolean \n \n Should any SQL errors be logged to the console in addition to being raised as an error? Defaults to True .", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-execute-fn", "page": "internals", "ref": "database-execute-fn", "title": "await db.execute_fn(fn)", "content": "Executes a given callback function against a read-only database connection running in a thread. The function will be passed a SQLite connection, and the return value from the function will be returned by the await . \n Example usage: \n def get_version(conn):\n return conn.execute(\n \"select sqlite_version()\"\n ).fetchall()[0][0]\n\n\nversion = await db.execute_fn(get_version)", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-execute-isolated-fn", "page": "internals", "ref": "database-execute-isolated-fn", "title": "await db.execute_isolated_fn(fn)", "content": "This method works is similar to execute_write_fn() but executes the provided function in an entirely isolated SQLite connection, which is opened, used and then closed again in a single call to this method. \n The prepare_connection() plugin hook is not executed against this connection. \n This allows plugins to execute database operations that might conflict with how database connections are usually configured. For example, running a VACUUM operation while bypassing any restrictions placed by the datasette-sqlite-authorizer plugin. \n Plugins can also use this method to load potentially dangerous SQLite extensions, use them to perform an operation and then have them safely unloaded at the end of the call, without risk of exposing them to other connections. \n Functions run using execute_isolated_fn() share the same queue as execute_write_fn() , which guarantees that no writes can be executed at the same time as the isolated function is executing. \n The return value of the function will be returned by this method. Any exceptions raised by the function will be raised out of the await line as well.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[{\"href\": \"https://github.com/datasette/datasette-sqlite-authorizer\", \"label\": \"datasette-sqlite-authorizer\"}]"} {"id": "internals:database-execute-write", "page": "internals", "ref": "database-execute-write", "title": "await db.execute_write(sql, params=None, block=True)", "content": "SQLite only allows one database connection to write at a time. Datasette handles this for you by maintaining a queue of writes to be executed against a given database. Plugins can submit write operations to this queue and they will be executed in the order in which they are received. \n This method can be used to queue up a non-SELECT SQL query to be executed against a single write connection to the database. \n You can pass additional SQL parameters as a tuple or dictionary. \n The method will block until the operation is completed, and the return value will be the return from calling conn.execute(...) using the underlying sqlite3 Python library. \n If you pass block=False this behavior changes to \"fire and forget\" - queries will be added to the write queue and executed in a separate thread while your code can continue to do other things. The method will return a UUID representing the queued task. \n Each call to execute_write() will be executed inside a transaction.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-execute-write-fn", "page": "internals", "ref": "database-execute-write-fn", "title": "await db.execute_write_fn(fn, block=True, transaction=True)", "content": "This method works like .execute_write() , but instead of a SQL statement you give it a callable Python function. Your function will be queued up and then called when the write connection is available, passing that connection as the argument to the function. \n The function can then perform multiple actions, safe in the knowledge that it has exclusive access to the single writable connection for as long as it is executing. \n \n fn needs to be a regular function, not an async def function. \n \n For example: \n def delete_and_return_count(conn):\n conn.execute(\"delete from some_table where id > 5\")\n return conn.execute(\n \"select count(*) from some_table\"\n ).fetchone()[0]\n\n\ntry:\n num_rows_left = await database.execute_write_fn(\n delete_and_return_count\n )\nexcept Exception as e:\n print(\"An error occurred:\", e) \n The value returned from await database.execute_write_fn(...) will be the return value from your function. \n If your function raises an exception that exception will be propagated up to the await line. \n By default your function will be executed inside a transaction. You can pass transaction=False to disable this behavior, though if you do that you should be careful to manually apply transactions - ideally using the with conn: pattern, or you may see OperationalError: database table is locked errors. \n If you specify block=False the method becomes fire-and-forget, queueing your function to be executed and then allowing your code after the call to .execute_write_fn() to continue running while the underlying thread waits for an opportunity to run your function. A UUID representing the queued task will be returned. Any exceptions in your code will be silently swallowed.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-execute-write-many", "page": "internals", "ref": "database-execute-write-many", "title": "await db.execute_write_many(sql, params_seq, block=True)", "content": "Like execute_write() but uses the sqlite3 conn.executemany() method. This will efficiently execute the same SQL statement against each of the parameters in the params_seq iterator, for example: \n await db.execute_write_many(\n \"insert into characters (id, name) values (?, ?)\",\n [(1, \"Melanie\"), (2, \"Selma\"), (2, \"Viktor\")],\n) \n Each call to execute_write_many() will be executed inside a transaction.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[{\"href\": \"https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executemany\", \"label\": \"conn.executemany()\"}]"} {"id": "internals:database-execute-write-script", "page": "internals", "ref": "database-execute-write-script", "title": "await db.execute_write_script(sql, block=True)", "content": "Like execute_write() but can be used to send multiple SQL statements in a single string separated by semicolons, using the sqlite3 conn.executescript() method. \n Each call to execute_write_script() will be executed inside a transaction.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[{\"href\": \"https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executescript\", \"label\": \"conn.executescript()\"}]"} {"id": "internals:database-hash", "page": "internals", "ref": "database-hash", "title": "db.hash", "content": "If the database was opened in immutable mode, this property returns the 64 character SHA-256 hash of the database contents as a string. Otherwise it returns None .", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[]"} {"id": "internals:database-results", "page": "internals", "ref": "database-results", "title": "Results", "content": "The db.execute() method returns a single Results object. This can be used to access the rows returned by the query. \n Iterating over a Results object will yield SQLite Row objects . Each of these can be treated as a tuple or can be accessed using row[\"column\"] syntax: \n info = []\nresults = await db.execute(\"select name from sqlite_master\")\nfor row in results:\n info.append(row[\"name\"]) \n The Results object also has the following properties and methods: \n \n \n .truncated - boolean \n \n Indicates if this query was truncated - if it returned more results than the specified page_size . If this is true then the results object will only provide access to the first page_size rows in the query result. You can disable truncation by passing truncate=False to the db.query() method. \n \n \n \n .columns - list of strings \n \n A list of column names returned by the query. \n \n \n \n .rows - list of sqlite3.Row \n \n This property provides direct access to the list of rows returned by the database. You can access specific rows by index using results.rows[0] . \n \n \n \n .first() - row or None \n \n Returns the first row in the results, or None if no rows were returned. \n \n \n \n .single_value() \n \n Returns the value of the first column of the first row of results - but only if the query returned a single row with a single column. Raises a datasette.database.MultipleValues exception otherwise. \n \n \n \n .__len__() \n \n Calling len(results) returns the (truncated) number of returned results.", "breadcrumbs": "[\"Internals for plugins\", \"Database class\"]", "references": "[{\"href\": \"https://docs.python.org/3/library/sqlite3.html#row-objects\", \"label\": \"Row objects\"}]"} {"id": "internals:datasette-absolute-url", "page": "internals", "ref": "datasette-absolute-url", "title": ".absolute_url(request, path)", "content": "request - Request \n \n The current Request object \n \n \n \n path - string \n \n A path, for example /dbname/table.json \n \n \n \n Returns the absolute URL for the given path, including the protocol and host. For example: \n absolute_url = datasette.absolute_url(\n request, \"/dbname/table.json\"\n)\n# Would return \"http://localhost:8001/dbname/table.json\" \n The current request object is used to determine the hostname and protocol that should be used for the returned URL. The force_https_urls configuration setting is taken into account.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-actors-from-ids", "page": "internals", "ref": "datasette-actors-from-ids", "title": "await .actors_from_ids(actor_ids)", "content": "actor_ids - list of strings or integers \n \n A list of actor IDs to look up. \n \n \n \n Returns a dictionary, where the keys are the IDs passed to it and the values are the corresponding actor dictionaries. \n This method is mainly designed to be used with plugins. See the actors_from_ids(datasette, actor_ids) documentation for details. \n If no plugins that implement that hook are installed, the default return value looks like this: \n {\n \"1\": {\"id\": \"1\"},\n \"2\": {\"id\": \"2\"}\n}", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-add-database", "page": "internals", "ref": "datasette-add-database", "title": ".add_database(db, name=None, route=None)", "content": "db - datasette.database.Database instance \n \n The database to be attached. \n \n \n \n name - string, optional \n \n The name to be used for this database . If not specified Datasette will pick one based on the filename or memory name. \n \n \n \n route - string, optional \n \n This will be used in the URL path. If not specified, it will default to the same thing as the name . \n \n \n \n The datasette.add_database(db) method lets you add a new database to the current Datasette instance. \n The db parameter should be an instance of the datasette.database.Database class. For example: \n from datasette.database import Database\n\ndatasette.add_database(\n Database(\n datasette,\n path=\"path/to/my-new-database.db\",\n )\n) \n This will add a mutable database and serve it at /my-new-database . \n Use is_mutable=False to add an immutable database. \n .add_database() returns the Database instance, with its name set as the database.name attribute. Any time you are working with a newly added database you should use the return value of .add_database() , for example: \n db = datasette.add_database(\n Database(datasette, memory_name=\"statistics\")\n)\nawait db.execute_write(\n \"CREATE TABLE foo(id integer primary key)\"\n)", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-add-memory-database", "page": "internals", "ref": "datasette-add-memory-database", "title": ".add_memory_database(name)", "content": "Adds a shared in-memory database with the specified name: \n datasette.add_memory_database(\"statistics\") \n This is a shortcut for the following: \n from datasette.database import Database\n\ndatasette.add_database(\n Database(datasette, memory_name=\"statistics\")\n) \n Using either of these pattern will result in the in-memory database being served at /statistics .", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-add-message", "page": "internals", "ref": "datasette-add-message", "title": ".add_message(request, message, type=datasette.INFO)", "content": "request - Request \n \n The current Request object \n \n \n \n message - string \n \n The message string \n \n \n \n type - constant, optional \n \n The message type - datasette.INFO , datasette.WARNING or datasette.ERROR \n \n \n \n Datasette's flash messaging mechanism allows you to add a message that will be displayed to the user on the next page that they visit. Messages are persisted in a ds_messages cookie. This method adds a message to that cookie. \n You can try out these messages (including the different visual styling of the three message types) using the /-/messages debugging tool.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-check-visibility", "page": "internals", "ref": "datasette-check-visibility", "title": "await .check_visibility(actor, action=None, resource=None, permissions=None)", "content": "actor - dictionary \n \n The authenticated actor. This is usually request.actor . \n \n \n \n action - string, optional \n \n The name of the action that is being permission checked. \n \n \n \n resource - string or tuple, optional \n \n The resource, e.g. the name of the database, or a tuple of two strings containing the name of the database and the name of the table. Only some permissions apply to a resource. \n \n \n \n permissions - list of action strings or (action, resource) tuples, optional \n \n Provide this instead of action and resource to check multiple permissions at once. \n \n \n \n This convenience method can be used to answer the question \"should this item be considered private, in that it is visible to me but it is not visible to anonymous users?\" \n It returns a tuple of two booleans, (visible, private) . visible indicates if the actor can see this resource. private will be True if an anonymous user would not be able to view the resource. \n This example checks if the user can access a specific table, and sets private so that a padlock icon can later be displayed: \n visible, private = await datasette.check_visibility(\n request.actor,\n action=\"view-table\",\n resource=(database, table),\n) \n The following example runs three checks in a row, similar to await .ensure_permissions(actor, permissions) . If any of the checks are denied before one of them is explicitly granted then visible will be False . private will be True if an anonymous user would not be able to view the resource. \n visible, private = await datasette.check_visibility(\n request.actor,\n permissions=[\n (\"view-table\", (database, table)),\n (\"view-database\", database),\n \"view-instance\",\n ],\n)", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-create-token", "page": "internals", "ref": "datasette-create-token", "title": ".create_token(actor_id, expires_after=None, restrict_all=None, restrict_database=None, restrict_resource=None)", "content": "actor_id - string \n \n The ID of the actor to create a token for. \n \n \n \n expires_after - int, optional \n \n The number of seconds after which the token should expire. \n \n \n \n restrict_all - iterable, optional \n \n A list of actions that this token should be restricted to across all databases and resources. \n \n \n \n restrict_database - dict, optional \n \n For restricting actions within specific databases, e.g. {\"mydb\": [\"view-table\", \"view-query\"]} . \n \n \n \n restrict_resource - dict, optional \n \n For restricting actions to specific resources (tables, SQL views and Canned queries ) within a database. For example: {\"mydb\": {\"mytable\": [\"insert-row\", \"update-row\"]}} . \n \n \n \n This method returns a signed API token of the format dstok_... which can be used to authenticate requests to the Datasette API. \n All tokens must have an actor_id string indicating the ID of the actor which the token will act on behalf of. \n Tokens default to lasting forever, but can be set to expire after a given number of seconds using the expires_after argument. The following code creates a token for user1 that will expire after an hour: \n token = datasette.create_token(\n actor_id=\"user1\",\n expires_after=3600,\n) \n The three restrict_* arguments can be used to create a token that has additional restrictions beyond what the associated actor is allowed to do. \n The following example creates a token that can access view-instance and view-table across everything, can additionally use view-query for anything in the docs database and is allowed to execute insert-row and update-row in the attachments table in that database: \n token = datasette.create_token(\n actor_id=\"user1\",\n restrict_all=(\"view-instance\", \"view-table\"),\n restrict_database={\"docs\": (\"view-query\",)},\n restrict_resource={\n \"docs\": {\n \"attachments\": (\"insert-row\", \"update-row\")\n }\n },\n)", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-databases", "page": "internals", "ref": "datasette-databases", "title": ".databases", "content": "Property exposing a collections.OrderedDict of databases currently connected to Datasette. \n The dictionary keys are the name of the database that is used in the URL - e.g. /fixtures would have a key of \"fixtures\" . The values are Database class instances. \n All databases are listed, irrespective of user permissions.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-ensure-permissions", "page": "internals", "ref": "datasette-ensure-permissions", "title": "await .ensure_permissions(actor, permissions)", "content": "actor - dictionary \n \n The authenticated actor. This is usually request.actor . \n \n \n \n permissions - list \n \n A list of permissions to check. Each permission in that list can be a string action name or a 2-tuple of (action, resource) . \n \n \n \n This method allows multiple permissions to be checked at once. It raises a datasette.Forbidden exception if any of the checks are denied before one of them is explicitly granted. \n This is useful when you need to check multiple permissions at once. For example, an actor should be able to view a table if either one of the following checks returns True or not a single one of them returns False : \n await datasette.ensure_permissions(\n request.actor,\n [\n (\"view-table\", (database, table)),\n (\"view-database\", database),\n \"view-instance\",\n ],\n)", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-get-database", "page": "internals", "ref": "datasette-get-database", "title": ".get_database(name)", "content": "name - string, optional \n \n The name of the database - optional. \n \n \n \n Returns the specified database object. Raises a KeyError if the database does not exist. Call this method without an argument to return the first connected database.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-get-permission", "page": "internals", "ref": "datasette-get-permission", "title": ".get_permission(name_or_abbr)", "content": "name_or_abbr - string \n \n The name or abbreviation of the permission to look up, e.g. view-table or vt . \n \n \n \n Returns a Permission object representing the permission, or raises a KeyError if one is not found.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-permission-allowed", "page": "internals", "ref": "datasette-permission-allowed", "title": "await .permission_allowed(actor, action, resource=None, default=...)", "content": "actor - dictionary \n \n The authenticated actor. This is usually request.actor . \n \n \n \n action - string \n \n The name of the action that is being permission checked. \n \n \n \n resource - string or tuple, optional \n \n The resource, e.g. the name of the database, or a tuple of two strings containing the name of the database and the name of the table. Only some permissions apply to a resource. \n \n \n \n default - optional: True, False or None \n \n What value should be returned by default if nothing provides an opinion on this permission check.\n Set to True for default allow or False for default deny.\n If not specified the default from the Permission() tuple that was registered using register_permissions(datasette) will be used. \n \n \n \n Check if the given actor has permission to perform the given action on the given resource. \n Some permission checks are carried out against rules defined in datasette.yaml , while other custom permissions may be decided by plugins that implement the permission_allowed(datasette, actor, action, resource) plugin hook. \n If neither metadata.json nor any of the plugins provide an answer to the permission query the default argument will be returned. \n See Built-in permissions for a full list of permission actions included in Datasette core.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-permissions", "page": "internals", "ref": "datasette-permissions", "title": ".permissions", "content": "Property exposing a dictionary of permissions that have been registered using the register_permissions(datasette) plugin hook. \n The dictionary keys are the permission names - e.g. view-instance - and the values are Permission() objects describing the permission. Here is a description of that object .", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-plugin-config", "page": "internals", "ref": "datasette-plugin-config", "title": ".plugin_config(plugin_name, database=None, table=None)", "content": "plugin_name - string \n \n The name of the plugin to look up configuration for. Usually this is something similar to datasette-cluster-map . \n \n \n \n database - None or string \n \n The database the user is interacting with. \n \n \n \n table - None or string \n \n The table the user is interacting with. \n \n \n \n This method lets you read plugin configuration values that were set in datasette.yaml . See Writing plugins that accept configuration for full details of how this method should be used. \n The return value will be the value from the configuration file - usually a dictionary. \n If the plugin is not configured the return value will be None .", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-remove-database", "page": "internals", "ref": "datasette-remove-database", "title": ".remove_database(name)", "content": "name - string \n \n The name of the database to be removed. \n \n \n \n This removes a database that has been previously added. name= is the unique name of that database.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-render-template", "page": "internals", "ref": "datasette-render-template", "title": "await .render_template(template, context=None, request=None)", "content": "template - string, list of strings or jinja2.Template \n \n The template file to be rendered, e.g. my_plugin.html . Datasette will search for this file first in the --template-dir= location, if it was specified - then in the plugin's bundled templates and finally in Datasette's set of default templates. \n If this is a list of template file names then the first one that exists will be loaded and rendered. \n If this is a Jinja Template object it will be used directly. \n \n \n \n context - None or a Python dictionary \n \n The context variables to pass to the template. \n \n \n \n request - request object or None \n \n If you pass a Datasette request object here it will be made available to the template. \n \n \n \n Renders a Jinja template using Datasette's preconfigured instance of Jinja and returns the resulting string. The template will have access to Datasette's default template functions and any functions that have been made available by other plugins.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[{\"href\": \"https://jinja.palletsprojects.com/en/2.11.x/api/#jinja2.Template\", \"label\": \"Template object\"}, {\"href\": \"https://jinja.palletsprojects.com/en/2.11.x/\", \"label\": \"Jinja template\"}]"} {"id": "internals:datasette-resolve-database", "page": "internals", "ref": "datasette-resolve-database", "title": ".resolve_database(request)", "content": "request - Request object \n \n A request object \n \n \n \n If you are implementing your own custom views, you may need to resolve the database that the user is requesting based on a URL path. If the regular expression for your route declares a database named group, you can use this method to resolve the database object. \n This returns a Database instance. \n If the database cannot be found, it raises a datasette.utils.asgi.DatabaseNotFound exception - which is a subclass of datasette.utils.asgi.NotFound with a .database_name attribute set to the name of the database that was requested.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-resolve-row", "page": "internals", "ref": "datasette-resolve-row", "title": ".resolve_row(request)", "content": "request - Request object \n \n A request object \n \n \n \n This method assumes your route declares named groups for database , table and pks . \n It returns a ResolvedRow named tuple instance with the following fields: \n \n \n db - Database \n \n The database object \n \n \n \n table - string \n \n The name of the table \n \n \n \n sql - string \n \n SQL snippet that can be used in a WHERE clause to select the row \n \n \n \n params - dict \n \n Parameters that should be passed to the SQL query \n \n \n \n pks - list \n \n List of primary key column names \n \n \n \n pk_values - list \n \n List of primary key values decoded from the URL \n \n \n \n row - sqlite3.Row \n \n The row itself \n \n \n \n If the database or table cannot be found it raises a datasette.utils.asgi.DatabaseNotFound exception. \n If the table does not exist it raises a datasette.utils.asgi.TableNotFound exception. \n If the row cannot be found it raises a datasette.utils.asgi.RowNotFound exception. This has .database_name , .table and .pk_values attributes, extracted from the request path.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-resolve-table", "page": "internals", "ref": "datasette-resolve-table", "title": ".resolve_table(request)", "content": "request - Request object \n \n A request object \n \n \n \n This assumes that the regular expression for your route declares both a database and a table named group. \n It returns a ResolvedTable named tuple instance with the following fields: \n \n \n db - Database \n \n The database object \n \n \n \n table - string \n \n The name of the table (or view) \n \n \n \n is_view - boolean \n \n True if this is a view, False if it is a table \n \n \n \n If the database or table cannot be found it raises a datasette.utils.asgi.DatabaseNotFound exception. \n If the table does not exist it raises a datasette.utils.asgi.TableNotFound exception - a subclass of datasette.utils.asgi.NotFound with .database_name and .table attributes.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-setting", "page": "internals", "ref": "datasette-setting", "title": ".setting(key)", "content": "key - string \n \n The name of the setting, e.g. base_url . \n \n \n \n Returns the configured value for the specified setting . This can be a string, boolean or integer depending on the requested setting. \n For example: \n downloads_are_allowed = datasette.setting(\"allow_download\")", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-sign", "page": "internals", "ref": "datasette-sign", "title": ".sign(value, namespace=\"default\")", "content": "value - any serializable type \n \n The value to be signed. \n \n \n \n namespace - string, optional \n \n An alternative namespace, see the itsdangerous salt documentation . \n \n \n \n Utility method for signing values, such that you can safely pass data to and from an untrusted environment. This is a wrapper around the itsdangerous library. \n This method returns a signed string, which can be decoded and verified using .unsign(value, namespace=\"default\") .", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[{\"href\": \"https://itsdangerous.palletsprojects.com/en/1.1.x/serializer/#the-salt\", \"label\": \"itsdangerous salt documentation\"}, {\"href\": \"https://itsdangerous.palletsprojects.com/\", \"label\": \"itsdangerous\"}]"} {"id": "internals:datasette-track-event", "page": "internals", "ref": "datasette-track-event", "title": "await .track_event(event)", "content": "event - Event \n \n An instance of a subclass of datasette.events.Event . \n \n \n \n Plugins can call this to track events, using classes they have previously registered. See Event tracking for details. \n The event will then be passed to all plugins that have registered to receive events using the track_event(datasette, event) hook. \n Example usage, assuming the plugin has previously registered the BanUserEvent class: \n await datasette.track_event(\n BanUserEvent(user={\"id\": 1, \"username\": \"cleverbot\"})\n)", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:datasette-unsign", "page": "internals", "ref": "datasette-unsign", "title": ".unsign(value, namespace=\"default\")", "content": "signed - any serializable type \n \n The signed string that was created using .sign(value, namespace=\"default\") . \n \n \n \n namespace - string, optional \n \n The alternative namespace, if one was used. \n \n \n \n Returns the original, decoded object that was passed to .sign(value, namespace=\"default\") . If the signature is not valid this raises a itsdangerous.BadSignature exception.", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:id1", "page": "internals", "ref": "id1", "title": ".get_internal_database()", "content": "Returns a database object for reading and writing to the private internal database .", "breadcrumbs": "[\"Internals for plugins\", \"Datasette class\"]", "references": "[]"} {"id": "internals:internals", "page": "internals", "ref": "internals", "title": "Internals for plugins", "content": "Many Plugin hooks are passed objects that provide access to internal Datasette functionality. The interface to these objects should not be considered stable with the exception of methods that are documented here.", "breadcrumbs": "[]", "references": "[]"}