Modify a query string on a url. The comments in the code should explain sufficiently. String_to_dict, and string_to_list are also useful for templatetags that require variable arguments.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | # app/templatetags/basic.py
from django import template
from django.utils.encoding import smart_unicode
from lib.utils import string_to_list, string_to_dict, get_query_string
from django.utils.safestring import mark_safe
register = template.Library()
@register.inclusion_tag('_response.html', takes_context=True)
def query_string(context, add=None, remove=None):
"""
Allows the addition and removal of query string parameters.
_response.html is just {{ response }}
Usage:
http://www.url.com/{% query_string "param_to_add=value, param_to_add=value" "param_to_remove, params_to_remove" %}
http://www.url.com/{% query_string "" "filter" %}filter={{new_filter}}
http://www.url.com/{% query_string "sort=value" "sort" %}
"""
# Written as an inclusion tag to simplify getting the context.
add = string_to_dict(add)
remove = string_to_list(remove)
params = dict( context['request'].GET.items())
response = get_query_string(params, add, remove)
return {'response': response }
# lib/utils.py
def get_query_string(p, new_params=None, remove=None):
"""
Add and remove query parameters. From `django.contrib.admin`.
"""
if new_params is None: new_params = {}
if remove is None: remove = []
for r in remove:
for k in p.keys():
if k.startswith(r):
del p[k]
for k, v in new_params.items():
if k in p and v is None:
del p[k]
elif v is not None:
p[k] = v
return mark_safe('?' + '&'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20'))
def string_to_dict(string):
"""
Usage::
{{ url|thumbnail:"width=10,height=20" }}
{{ url|thumbnail:"width=10" }}
{{ url|thumbnail:"height=20" }}
"""
kwargs = {}
if string:
string = str(string)
if ',' not in string:
# ensure at least one ','
string += ','
for arg in string.split(','):
arg = arg.strip()
if arg == '': continue
kw, val = arg.split('=', 1)
kwargs[kw] = val
return kwargs
def string_to_list(string):
"""
Usage::
{{ url|thumbnail:"width,height" }}
"""
args = []
if string:
string = str(string)
if ',' not in string:
# ensure at least one ','
string += ','
for arg in string.split(','):
arg = arg.strip()
if arg == '': continue
args.append(arg)
return args
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Great, thanks - this totally met my need.
A few notes for others implementing this:
You need to add
"django.core.context_processors.request"
, to yourTEMPLATE_CONTEXT_PROCESSORS
setting.You need to add this import to your lib/utils.py (or equivalent):
And it is also worth mentioning that you need to create _response.html
#
This is terrific. I don't use GET parameters all that often, but for filtering/sorting content, this snippet really proved helpful. Thanks so much.
#
A great piece of code but it doesn't work with MultipleChoiceField !
The QueryDict object cannot deal with a list values, you have the use the lists function.
A possible implementation might be (for the get_query_string method):
...
def get_query_string(p, new_params=None, remove=None):
#
Have just posted this on JHsaunders' snippet, but it seems to apply here too: as it stands, this is vulnerable to a cross-site scripting attack because the URL variables previously provided by the user are passed through mark_safe with no escaping, apart from replacing space characters. This can be fixed by adding 'import urllib' to lib/utils.py, and changing the last line of get_query_string to:
(Also, to be completely correct even when autoescaping is turned off, I suspect it should be using a plain '&' to delimit the arguments and passing it back as an unsafe string for the template layer to escape - but I'll leave that for someone else to confirm...)
#
Please login first before commenting.