Preserve repeated query keys with parse_qsl
Also published in our primary archive.
Repeated query keys are meaningful in many URL conventions. For example, a fixture URL may use two tag fields to represent two selected tags. parse_qs() groups values by key, which is useful when lookup is the goal, but it returns a dictionary and does not express the original sequence as a list of individual fields. Use parse_qsl() when the ordered sequence of name/value pairs is the data you need.
The example first isolates the query with urlsplit(), then calls parse_qsl(). Its resulting list contains both tag pairs in their input order, followed by sort=name. The assertion compares the full list, so it verifies that this fixture retained the duplicate key and its ordering. Printing the list provides deterministic output suitable for a small parsing check.
parse_qsl() decodes form-style query data: a plus sign represents a space and percent escapes are decoded using UTF-8 by default. By default, blank fields are discarded; pass keep_blank_values=True when blanks must be represented. Its max_num_fields parameter, added in Python 3.8, can set a field-count limit for application input. This example uses APIs available in Python 3.2+ and does not depend on that newer option. Consult the official urllib.parse documentation.
AI assistance disclosure: this article was drafted with AI assistance and should be reviewed against the target protocol’s query conventions.
from urllib.parse import parse_qsl, urlsplit
fixture_url = "https://fixtures.example.test/items?tag=python&tag=testing&sort=name"
pairs = parse_qsl(urlsplit(fixture_url).query, keep_blank_values=True)
assert pairs == [
("tag", "python"),
("tag", "testing"),
("sort", "name"),
]
print(pairs)
[('tag', 'python'), ('tag', 'testing'), ('sort', 'name')]