utils.path_with_added_args() improvements

* Now covered by unit tests
* Preserves original order
* Can handle multiple args of the same name, e.g. ?bar=1&bar=2
pull/386/head
Simon Willison 2018-05-12 18:35:25 -03:00
rodzic 1c815207cc
commit 70ff615f1b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 17E2DEA2588B7F52
3 zmienionych plików z 29 dodań i 9 usunięć

Wyświetl plik

@ -150,17 +150,17 @@ def path_with_added_args(request, args, path=None):
if isinstance(args, dict): if isinstance(args, dict):
args = args.items() args = args.items()
arg_keys = set(a[0] for a in args) arg_keys = set(a[0] for a in args)
current = [ current = []
(key, value) for key, values in request.args.items():
for key, value in request.raw_args.items() current.extend(
if key not in arg_keys [(key, value) for value in values if key not in arg_keys]
] )
current.extend([ current.extend([
(key, value) (key, value)
for key, value in args for key, value in args
if value is not None if value is not None
]) ])
query_string = urllib.parse.urlencode(sorted(current)) query_string = urllib.parse.urlencode(current)
if query_string: if query_string:
query_string = '?{}'.format(query_string) query_string = '?{}'.format(query_string)
return path + query_string return path + query_string

Wyświetl plik

@ -65,7 +65,7 @@ def test_add_filter_redirects(app_client):
path = path_base + '?foo=bar&' + filter_args path = path_base + '?foo=bar&' + filter_args
response = app_client.get(path, allow_redirects=False, gather_request=False) response = app_client.get(path, allow_redirects=False, gather_request=False)
assert response.status == 302 assert response.status == 302
assert response.headers['Location'].endswith('?content__startswith=x&foo=bar') assert response.headers['Location'].endswith('?foo=bar&content__startswith=x')
# Test that op with a __x suffix overrides the filter value # Test that op with a __x suffix overrides the filter value
path = path_base + '?' + urllib.parse.urlencode({ path = path_base + '?' + urllib.parse.urlencode({
@ -100,7 +100,7 @@ def test_existing_filter_redirects(app_client):
response = app_client.get(path, allow_redirects=False, gather_request=False) response = app_client.get(path, allow_redirects=False, gather_request=False)
assert response.status == 302 assert response.status == 302
assert response.headers['Location'].endswith( assert response.headers['Location'].endswith(
'?age__gte=22&age__lt=30&name__contains=hello&name__contains=world' '?name__contains=hello&age__gte=22&age__lt=30&name__contains=world'
) )
# Setting _filter_column_3 to empty string should remove *_3 entirely # Setting _filter_column_3 to empty string should remove *_3 entirely
@ -109,7 +109,7 @@ def test_existing_filter_redirects(app_client):
response = app_client.get(path, allow_redirects=False, gather_request=False) response = app_client.get(path, allow_redirects=False, gather_request=False)
assert response.status == 302 assert response.status == 302
assert response.headers['Location'].endswith( assert response.headers['Location'].endswith(
'?age__gte=22&name__contains=hello&name__contains=world' '?name__contains=hello&age__gte=22&name__contains=world'
) )
# ?_filter_op=exact should be removed if unaccompanied by _fiter_column # ?_filter_op=exact should be removed if unaccompanied by _fiter_column

Wyświetl plik

@ -6,6 +6,7 @@ from datasette import utils
import json import json
import os import os
import pytest import pytest
from sanic.request import Request
import sqlite3 import sqlite3
import tempfile import tempfile
from unittest.mock import patch from unittest.mock import patch
@ -22,6 +23,25 @@ def test_urlsafe_components(path, expected):
assert expected == utils.urlsafe_components(path) assert expected == utils.urlsafe_components(path)
@pytest.mark.parametrize('path,added_args,expected', [
('/foo', {'bar': 1}, '/foo?bar=1'),
('/foo?bar=1', {'baz': 2}, '/foo?bar=1&baz=2'),
('/foo?bar=1&bar=2', {'baz': 3}, '/foo?bar=1&bar=2&baz=3'),
('/foo?bar=1', {'bar': None}, '/foo'),
# Test order is preserved
('/?_facet=prim_state&_facet=area_name', {
'prim_state': 'GA'
}, '/?_facet=prim_state&_facet=area_name&prim_state=GA'),
])
def test_path_with_added_args(path, added_args, expected):
request = Request(
path.encode('utf8'),
{}, '1.1', 'GET', None
)
actual = utils.path_with_added_args(request, added_args)
assert expected == actual
@pytest.mark.parametrize('row,pks,expected_path', [ @pytest.mark.parametrize('row,pks,expected_path', [
({'A': 'foo', 'B': 'bar'}, ['A', 'B'], 'foo,bar'), ({'A': 'foo', 'B': 'bar'}, ['A', 'B'], 'foo,bar'),
({'A': 'f,o', 'B': 'bar'}, ['A', 'B'], 'f%2Co,bar'), ({'A': 'f,o', 'B': 'bar'}, ['A', 'B'], 'f%2Co,bar'),