import urllib try: from urlparse import parse_qs except ImportError: from cgi import parse_qs def url_params(url, **kwargs): bits = url.split('?') query_vars = {} if len(bits) > 1: query_vars = parse_qs(bits[1], keep_blank_values=1) for key, value in query_vars.items(): # value is always a list - kill it as we want to overwrite it query_vars[key] = value[0] query_vars.update(kwargs) new_dict = {} for key, value in query_vars.items(): # filter out empty values if str(value) != '0' and not value: continue else: new_dict[key] = value kwargs = new_dict query_string = '' url = bits[0] if kwargs: query_string = urllib.urlencode(kwargs) if query_string: url = '%s?%s' % (url, query_string) return url if __name__ == '__main__': import unittest class UrlTest(unittest.TestCase): def test_single_query_string(self): """Tests that a query string is appended correctly""" new_url = url_params('/something/something', blah='true') self.assertEqual(new_url, '/something/something?blah=true') def test_multi_query_string(self): """Tests that multiple parameters to a query string are appended""" new_url = url_params('/something/something', blah='true', something='somethingelse') self.assertEqual(new_url, '/something/something?blah=true&something=somethingelse') def test_no_query_string(self): """Tests that no query string is valid""" new_url = url_params('/blah/foo') self.assertEqual(new_url, '/blah/foo') def test_existing_query_string(self): """Tests that old query strings aren't overwritten""" new_url = url_params('/blah/foo?thing=other&blah=yes') self.assertEqual(new_url, '/blah/foo?thing=other&blah=yes') def test_overwrite_query_string(self): """tests that query parameters are overwritten by arguments""" new_url = url_params('/blah/foo?thing=yes', thing='no') self.assertEqual(new_url, '/blah/foo?thing=no') def test_delete_query_string(self): """tests that query parameters are deleted by explicitly killing them""" new_url = url_params('/blah/foo?thing=yes', thing=False) self.assertEqual(new_url, '/blah/foo') def test_extra_parameter(self): """Tests that extra false parameters don't kill the reverser""" new_url = url_params('/blah/foo', thing=False) self.assertEqual(new_url, '/blah/foo') def test_falsiness(self): """Test that only False, empty strings, and None gets dropped""" new_url = url_params('/blah/foo', thing=None) self.assertEqual(new_url, '/blah/foo') new_url = url_params('/blah/foo', thing=False) self.assertEqual(new_url, '/blah/foo') new_url = url_params('/blah/foo', thing='') self.assertEqual(new_url, '/blah/foo') new_url = url_params('/blah/foo', thing=0) self.assertEqual(new_url, '/blah/foo?thing=0') new_url = url_params('/blah/foo', thing=1) self.assertEqual(new_url, '/blah/foo?thing=1') unittest.main()