Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python query strings: retain blank fields and reject repeated keys

Last updated: 1 Oct 20265 min read
tutorial
IntermediateBy AITrove Editorial

Parsing a query into pairs preserves duplicate names long enough to reject them.

Download Python source kit

Operation contract

An owned pair list encodes a slash in the receipt identifier before transmission. The decoder retains blank values, requires exactly one receipt and one amount, and rejects repeated fields. It also caps the field count before building an application mapping.

Failure boundary

parse_qsl is a field parser, not a complete request validator. Percent escapes, Unicode normalization, numeric ranges, and authorization need separate rules. A query field limit does not cap the total request-line bytes; impose a byte limit at the receiving layer too.

Working program

python
from urllib.parse import parse_qsl, urlencode

def parse_receipt_query(query):
    pairs = parse_qsl(query, keep_blank_values=True, strict_parsing=True,
                      errors="strict", max_num_fields=2)
    if len(pairs) != 2 or {name for name, _ in pairs} != {"receipt", "amount"}:
        raise ValueError("wrong or repeated fields")
    fields = dict(pairs)
    if not fields["receipt"] or not fields["amount"].isascii() or not fields["amount"].isdecimal():
        raise ValueError("invalid field")
    return fields["receipt"], int(fields["amount"])

wire_query = urlencode([("receipt", "R/47"), ("amount", "73")])
print("wire", wire_query)
print("parsed", parse_receipt_query(wire_query))
for rejected_query in ("receipt=R-47&receipt=R-73", "receipt=&amount=73",
                       "receipt=R-47&amount=73&mode=paid"):
    try:
        parse_receipt_query(rejected_query)
    except ValueError:
        print("rejected", rejected_query.split("&")[0])

Output

Output
wire receipt=R%2F47&amount=73
parsed ('R/47', 73)
rejected receipt=R-47
rejected receipt=
rejected receipt=R-47

Costs and limits

Parsing scans the query and allocates decoded field strings. The two-field ceiling bounds field count only; the caller must also cap query bytes before parsing.

Common Mistakes

  • Converting to a dict first silently discards the fact that a key repeated.
  • The default parser may discard blank values unless asked to retain them.
  • Field count is not a request-byte budget.

Connected lessons

Test this contract.

python
query-field-duplicates
Storage details