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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 | from django.core.urlresolvers import reverse
from django.template import FilterExpression
from django.template import Library, Node, TemplateSyntaxError, resolve_variable
from re import split
from urllib import quote,unquote
import re
register = Library()
class LinkNode(Node):
def __init__(self, viewname, args, kwargs, add_to_current_link=False):
self.viewname = viewname
self.kwargs = kwargs
self.args = args
self.add_to_current_link = add_to_current_link
def render(self,context):
req = resolve_variable('request',context)
args = [isinstance(k,FilterExpression) and k.resolve(context) or k for k in self.args]
kwargs = req.GET.copy()
for k,v in self.kwargs.items():
if isinstance(v, FilterExpression) and v.token:
kwargs[k] = v.resolve(context)
elif v:
kwargs[k] = v
try:
url = not self.add_to_current_link and reverse(viewname=self.viewname, args=args, kwargs=None) or req.path
except:
url = req.path
# check to see if named arguments have been passed
query_started = url.find('?') > -1
query_string = ""
raw_url = unquote(url)
for k,values in kwargs.items():
if not isinstance(values,list):
values = [values]
params_added = "&".join(
[quote(k) + "=" + quote(isinstance(v,str) and v or str(v)) for v in values
if v and (not query_started or not re.search(r"\b" + re.escape(k + "=" + v) + r"\b", raw_url))])
if params_added: query_string += "&" + params_added
if not query_started and len(query_string) > 0:
query_string = "?" + query_string[1:]
return url + query_string
def link_persist(parser, token):
"""Url Tag that persists GET variables
It has the same behaviour as the standard url tag
found in django.template.defaulttags.
But GET variables are passed by default to the 'reverse' url
method that builds the final url. Specified parameters override
GET parameters.
Usage: {% link_persist viewname arg1, arg2, ... karg1=val1, karg2=val2 ... %}
This has been tested with Django version 0.96"""
bits = token.contents.split(' ', 2)
if len(bits) < 2:
raise TemplateSyntaxError, "'%s' takes at least one argument (path to a view)" % bits[0]
args = []
kwargs = {}
if len(bits) > 2:
for arg in bits[2].split(','):
if '=' in arg:
k, v = arg.split('=', 1)
kwargs[k] = parser.compile_filter(v)
else:
args.append(parser.compile_filter(arg))
return LinkNode(bits[1], args, kwargs)
def link_add(parser, token):
"""Tag that adds parameters to the current url.
Usage: {% link_add karg1=val1, karg2=val2 ... %}
This has been tested with Django version 0.96"""
bits = token.contents.split(' ', 2)
args = []
kwargs = {}
if len(bits) > 1:
for arg in bits[1].split(','):
if '=' in arg:
k, v = arg.split('=', 1)
kwargs[k] = parser.compile_filter(v)
return LinkNode(None, args, kwargs, True)
register.tag('link_persist', link_persist)
register.tag('link_add', link_add)
|
Comments
That looks a bit complicated for something that should be so simple. I use this, which works for all my purposes:
It works great for dealing with paged content:
#
That's cool, although my needs a little more complicated.
I'll work on simplifying it ... my python-foo is a little rusty :)
#
I used this snippet for quite some time and finally found a bug :-)
You have the following line in the LinkNode:
for k,values in kwargs.items():
but it must be:
for k,values in kwargs.lists():
otherwise you will only get the last value for each key.
#