Commits

Branko Vukelic committed 25dff1b Merge

Comments (0)

Files changed (7)

 + ``query_dict``: ``QueryDict`` instance containing the URL's query parameters
 + ``query``: similar to ``query_dict`` but also does more when assigning
 + ``query_string``: URL's query string
++ ``hash``: MD5 hexdigest of the full path including query parameters
 
 UrlHelper.path
 --------------
     u.query_string = 'foo=1&bar=2'       # this works
     u.query_string = dict(foo=1, bar=2)  # but this doesn't
 
+UrlHelper.hash
+--------------
+
+Returns the MD5 hexdigest of the full path including query parameters. This can
+be useful for use with caching and other situations where we need to
+differentiate same paths with different query parameters. ::
+
+    u = UrlHelper('/foo/bar')
+    u.query = dict(foo=1) # URL is now '/foo/bar?foo=1'
+    u.hash  # returns '06f0a42bdd474f053fb1343165a31d42'
+
 UrlHelper.get_query_string(**kwargs)
 ------------------------------------
 
 
     u = UrlHelper('/foo')
     u.update_query_data(bar=[1, 2, 3])
-    u.query_string  # returns '/foo?bar=1&bar=2&bar=3'
+    u.query_string  # returns 'bar=1&bar=2&bar=3'
 
 UrlHelper.get_path()
 --------------------
 Same as ``UrlHelper.get_full_path()`` method, but returns the full path quoted
 so that it can be used as an URL parameter value.
 
+UrlHelper.del_param(param)
+--------------------------
+
+Delete a single query parameter. ::
+
+    u = UrlHelper('/foo?bar=1&baz=2')
+    u.del_param('baz')
+    u.get_full_path() # returns '/foo?bar=1'
+
+UrlHelper.del_params([param, param...])
+---------------------------------------
+
+Delete multiple parameters. If no parameters are specified, _all_ parameters
+are removed. ::
+
+    u = UrlHelper('/foo?bar=1&baz=2&foo=3')
+    u.del_params('foo', 'bar')
+    u.get_full_path() # returns '/foo?baz=2'
+
+    u = UrlHelper('/foo?bar=1&baz=2&foo=3')
+    u.del_params()
+    u.get_full_path() # returns '/foo'
+
 ContextProcessors
 =================
 
 
 URL tools currently has only one template tag, which is an assignment tag.
 
+{% add_params %}
+----------------
+
+This template tag outputs a path with query string parameters given as keyword
+arguments. For instance, if we are on a page at ``/foo``, we can use this tag::
+
+    {% add_params request.get_full_path foo='bar' %}
+
+and the output would be::
+
+    /foo?foo=bar
+
+Existing URL parameters are overridden by the ones specified as keyword
+arguments.
+
+{% del_params %}
+----------------
+
+This tag outputs a path stripped of specified parameters, or all query 
+parameters if none are specified. For example, if we are on the
+``/foo?bar=1&baz=2`` URL::
+
+    {% del_param request.get_full_path 'bar' %}
+
+outputs::
+
+    /foo?baz=2
+
+and ::
+
+    {% del_params request.get_full_path %}
+
+outputs::
+
+    /foo
+
+
 {% url_params %}
----------------------
+----------------
 
 This tag is used as an assignment tag. Its first argument is an URL, followed
 by any number of keyword arguments that represent the URL parameters. For
     name='django-url-tools',
     description='Django helpers for dealing with URLs in templates',
     long_description=open('README.rst').read(),
-    version='0.0.1',
+    version='0.0.4',
     packages=['url_tools', 'url_tools.templatetags'],
     author='Monwara LLC',
     author_email='branko@monwara.com',

tests/test_add_params.py

+from __future__ import absolute_import, unicode_literals
+
+from unittest import TestCase
+
+from url_tools.templatetags.urls import add_params
+from url_tools.helper import UrlHelper
+
+
+class AddParamsTestCase(TestCase):
+    def test_add_params_basicaly_works(self):
+        self.assertEqual(
+            add_params('/foo/bar?baz=0#frag', foo=1, bar=2),
+            '/foo/bar?bar=2&foo=1&baz=0#frag'
+        )
+
+    def test_add_parasm_with_helper_instance(self):
+        self.assertEqual(
+            add_params(UrlHelper('/foo/bar?baz=0#frag'), foo=1, bar=2),
+            '/foo/bar?bar=2&foo=1&baz=0#frag'
+        )

tests/test_del_params.py

+from __future__ import absolute_import, unicode_literals
+
+from unittest import TestCase
+
+from url_tools.templatetags.urls import del_params
+from url_tools.helper import UrlHelper
+
+
+class DelParamsTestCase(TestCase):
+    def test_del_params_basic(self):
+        self.assertEqual(
+            del_params('/foo?bar=1&baz=2', 'baz'),
+            '/foo?bar=1'
+        )
+
+    def test_del_paramss_all(self):
+        self.assertEqual(
+            del_params('/foo?bar=1&baz=2'),
+            '/foo'
+        )
+
+    def test_del_params_takes_helper_instance(self):
+        self.assertEqual(
+            del_params(UrlHelper('/foo?bar=1&baz=2'), 'bar'),
+            '/foo?baz=2'
+        )

tests/test_url_helper.py

         u.query = dict(foo=1, bar=2)
         u.fragment = 'baz'
         self.assertEqual(str(u), '/foo/bar?foo=1&bar=2#baz')
+
+    def test_use_with_URL_as_param_value(self):
+        u = UrlHelper('/foo/bar/')
+        u.query = {'redir': '/foo/bar/baz?test=1'}
+        self.assertEqual(u.get_full_path(),
+                         '/foo/bar/?redir=%2Ffoo%2Fbar%2Fbaz%3Ftest%3D1')
+
+    def test_hashing_basically_works(self):
+        u = UrlHelper('/foo/bar/')
+        self.assertEqual(u.hash, '1c184f3891344400380281315d9e7388')
+
+    def test_hashling_with_query_string(self):
+        u = UrlHelper('/foo/bar')
+        u.query = dict(foo=1)
+        self.assertEqual(u.hash, '06f0a42bdd474f053fb1343165a31d42')
+
+    def test_delete_key(self):
+        u = UrlHelper('/foo/bar?foo=1&bar=2')
+        u.del_param('foo')
+        self.assertEqual(u.get_full_path(), '/foo/bar?bar=2')
+
+    def test_delete_multiple_keys(self):
+        u = UrlHelper('/foo/bar?foo=1&bar=2')
+        u.del_params('foo', 'bar')
+        self.assertEqual(u.get_full_path(), '/foo/bar')
+
+    def test_delete_fails_silently(self):
+        u = UrlHelper('/foo/bar?foo=1&bar=2')
+        u.del_params('foo', 'baz')  # baz doesn't exist
+        self.assertEqual(u.get_full_path(), '/foo/bar?bar=2')
+
+    def test_delete_multiple_without_arguments(self):
+        u = UrlHelper('/foo/bar?foo=1&bar=2')
+        u.del_params()
+        self.assertEqual(u.get_full_path(), '/foo/bar')

url_tools/helper.py

 
 import urllib
 import urlparse
+import hashlib
 
 from django.http.request import QueryDict
 from django.utils.encoding import iri_to_uri
 
 
 class UrlHelper(object):
+    _hash = None
+
     def __init__(self, full_path):
         # parse the path
         r = urlparse.urlparse(full_path)
         return self.query_dict
 
     def update_query_data(self, **kwargs):
+        self._hash = None
         for key in kwargs:
             val = kwargs[key]
             if hasattr(val, '__iter__'):
     def get_full_quoted_path(self, **kwargs):
         return urllib.quote_plus(self.get_full_path(**kwargs), safe='/')
 
+    def del_param(self, param):
+        try:
+            del self.query_dict[param]
+        except KeyError:
+            pass # Fail silently
+
+    def del_params(self, *params):
+        if not params:
+            self.query = {}
+            return
+        for param in params:
+            self.del_param(param)
+
+    @property
+    def hash(self):
+        if self._hash:
+            return self._hash
+        md5 = hashlib.md5()
+        md5.update(self.get_full_path())
+        self._hash = md5.hexdigest()
+        return self._hash
+
     @property
     def query(self):
         return self.get_query_data()
 
     @query.setter
     def query(self, value):
+        self._hash = None
         if type(value) is dict:
             self.query_dict = QueryDict('', mutable=True)
             self.update_query_data(**value)
 
     @query_string.setter
     def query_string(self, value):
+        self._hash = None
         self.query_dict = QueryDict(value, mutable=True)
 
     def __str__(self):

url_tools/templatetags/urls.py

 register = template.Library()
 
 
+@register.simple_tag
+def add_params(url, **kwargs):
+    if type(url) in [str, unicode]:
+        url = UrlHelper(url)
+    try:
+        url.update_query_data(**kwargs)
+        return url.get_full_path()
+    except:
+        return ''
+
+
+@register.simple_tag
+def del_params(url, *args):
+    if type(url) in [str, unicode]:
+        url = UrlHelper(url)
+    try:
+        url.del_params(*args)
+        return url.get_full_path()
+    except:
+        return ''
+
+
 @register.assignment_tag
 def url_params(url, **kwargs):
     u = UrlHelper(url)
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.