Mike Orr avatar Mike Orr committed c25b5af

Fix bug handling existing query params; add support for multiple values.

Comments (0)

Files changed (3)

   - Urlencode ``urlify()`` return value in case it contains special
     characters like "?". Reported by mcd34@gmail.com.
 
+* webhelpers.util:
+
+  - Fix bug in handling existing query strings. Support multiple values per
+    parameter.
+
 1.1 (2010-08-09)
 ----------------
 

docs/whats_new.rst

 "MarkupSafe" package, which Mako and Pylons have also switched to.  MarkupSafe
 has a C speedup for escaping, escapes single-quotes for greater security (to
 close a potential XSS attack route), and adds new methods to ``literal``.
-
-* **literal** is now a subclass of ``markupsafe.Markup``
-
-* **escape** is ``markupsafe.escape_silent``
-
-*Note*: ``escape_silent`` does not exist yet in MarkupSafe 0.9.3, but
-WebHelpers has a fallback. 
+**literal** is now a subclass of ``markupsafe.Markup``
+**escape** is ``markupsafe.escape_silent``
+(Note: ``escape_silent`` does not exist yet in MarkupSafe 0.9.3, but
+WebHelpers has a fallback.)
 
 *webhelpers.html.tags:* The ``text()`` helper has a "type" argument for new
 HTML 5 input types.
 generated by the ``form()`` helper**: the IDs clash if there are multiple forms
 on the page. To create a hidden field with an ID, call ``hidden()`` directly.
 
+*webhelpers.util:* ``update_params`` now supports query parameters with
+multiple values.
+
 Version 1.1
 -----------
 

webhelpers/util.py

     from cgi import parse_qs
 
 
-def update_params(url, **params):
+def update_params(_url, _debug=False, **params):
     """Update query parameters in a URL.
 
-    ``url`` is any URL.
-    ``params`` are query parameters to add or replace. If any value is None,
-    the corresponding parameter is deleted from the URL if present.
+    ``_url`` is any URL, with or without a query string.
+
+    ``\*\*params`` are query parameters to add or replace. Each value may be a
+    string, a list of strings, or None. Passing a list generates multiple
+    values for the same parameter. Passing None deletes the corresponding
+    parameter if present.
 
     Return the new URL.
 
-    This function does not handle multiple parameters with the same name.
-    It will arbitrarily choose one value and discard the others.
-
     *Debug mode:* if a pseudo-parameter ``_debug=True`` is passed,
     return a tuple: ``[0]`` is the URL without query string or fragment,
     ``[1]`` is the final query parameters as a dict, and ``[2]`` is the
     'http://example.com/foo?new1=NEW1#myfrag'
     >>> update_params("http://example.com/foo?new1=OLD1#myfrag", new1="NEW1", _debug=True)
     ('http://example.com/foo', {'new1': 'NEW1'}, 'myfrag')
+    >>> update_params("http://www.mau.de?foo=2", brrr=3)
+    'http://www.mau.de?foo=2&brrr=3'
+    >>> update_params("http://www.mau.de?foo=A&foo=B", foo=["C", "D"])
+    'http://www.mau.de?foo=C&foo=D'
 
     """
-    debug = params.pop("_debug", False)
-    orig_url = url
-    url, fragment = urlparse.urldefrag(url)
+    url, fragment = urlparse.urldefrag(_url)
     if "?" in url:
         url, qs = url.split("?", 1)
         query = parse_qs(qs)
             query[key] = value
         elif key in query:
             del query[key]
-    if debug:
+    if _debug:
         return url, query, fragment
-    qs = urllib.urlencode(query)
+    qs = urllib.urlencode(query, True)
     if qs:
         qs = "?" + qs
     if fragment:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.