From a6ff123de5464806441f6a6f95145c9a83b7f20b Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sun, 12 Dec 2021 12:01:51 -0800 Subject: [PATCH] keep_blank_values=True when parsing query_string, closes #1551 Refs #1518 --- datasette/utils/asgi.py | 2 +- datasette/views/table.py | 11 +++-------- tests/test_internals_request.py | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/datasette/utils/asgi.py b/datasette/utils/asgi.py index ad137fa9..cd3ec654 100644 --- a/datasette/utils/asgi.py +++ b/datasette/utils/asgi.py @@ -97,7 +97,7 @@ class Request: @property def args(self): - return MultiParams(parse_qs(qs=self.query_string)) + return MultiParams(parse_qs(qs=self.query_string, keep_blank_values=True)) @property def actor(self): diff --git a/datasette/views/table.py b/datasette/views/table.py index f58b78f5..59010723 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -393,21 +393,16 @@ class TableView(RowTableShared): nocount = True nofacet = True - # Ensure we don't drop anything with an empty value e.g. ?name__exact= - args = MultiParams( - urllib.parse.parse_qs(request.query_string, keep_blank_values=True) - ) - # Special args start with _ and do not contain a __ # That's so if there is a column that starts with _ # it can still be queried using ?_col__exact=blah special_args = {} other_args = [] - for key in args: + for key in request.args: if key.startswith("_") and "__" not in key: - special_args[key] = args[key] + special_args[key] = request.args[key] else: - for v in args.getlist(key): + for v in request.args.getlist(key): other_args.append((key, v)) # Handle ?_filter_column and redirect, if present diff --git a/tests/test_internals_request.py b/tests/test_internals_request.py index cd956f3f..01c93eec 100644 --- a/tests/test_internals_request.py +++ b/tests/test_internals_request.py @@ -121,3 +121,19 @@ def test_request_properties(path, query_string, expected_full_path): assert request.path == path assert request.query_string == query_string assert request.full_path == expected_full_path + + +def test_request_blank_values(): + query_string = "a=b&foo=bar&foo=bar2&baz=" + path_with_query_string = "/?" + query_string + scope = { + "http_version": "1.1", + "method": "POST", + "path": "/", + "raw_path": path_with_query_string.encode("latin-1"), + "query_string": query_string.encode("latin-1"), + "scheme": "http", + "type": "http", + } + request = Request(scope, None) + assert request.args._data == {"a": ["b"], "foo": ["bar", "bar2"], "baz": [""]}