1
1
from collections import OrderedDict
2
2
from itertools import islice
3
+ from urllib .parse import urlencode
3
4
4
5
from django .core .exceptions import ImproperlyConfigured
5
6
from django .urls import reverse
@@ -65,7 +66,7 @@ class LinkTransform:
65
66
accessor = None
66
67
attrs = None
67
68
68
- def __init__ (self , url = None , accessor = None , attrs = None , reverse_args = None ):
69
+ def __init__ (self , url = None , accessor = None , attrs = None , reverse_args = None , query = None , fragment = None ):
69
70
"""
70
71
arguments:
71
72
url (callable): If supplied, the result of this callable will be used as ``href`` attribute.
@@ -79,6 +80,8 @@ def __init__(self, url=None, accessor=None, attrs=None, reverse_args=None):
79
80
self .url = url
80
81
self .attrs = attrs
81
82
self .accessor = accessor
83
+ self .query = query
84
+ self .fragment = fragment
82
85
83
86
if isinstance (reverse_args , (list , tuple )):
84
87
viewname , args = reverse_args
@@ -95,23 +98,33 @@ def compose_url(self, **kwargs):
95
98
record = kwargs ["record" ]
96
99
97
100
if self .reverse_args .get ("viewname" , None ) is not None :
98
- return self .call_reverse (record = record )
99
-
100
- if bound_column is None and self .accessor is None :
101
- accessor = Accessor ("" )
101
+ url = self .call_reverse (record = record )
102
102
else :
103
- accessor = Accessor (self .accessor if self .accessor is not None else bound_column .name )
104
- context = accessor .resolve (record )
105
- if not hasattr (context , "get_absolute_url" ):
106
- if hasattr (record , "get_absolute_url" ):
107
- context = record
103
+ if bound_column is None and self .accessor is None :
104
+ accessor = Accessor ("" )
108
105
else :
109
- raise TypeError (
110
- "for linkify=True, '{}' must have a method get_absolute_url" .format (
111
- str (context )
106
+ accessor = Accessor (self .accessor if self .accessor is not None else bound_column .name )
107
+ context = accessor .resolve (record )
108
+ if not hasattr (context , "get_absolute_url" ):
109
+ if hasattr (record , "get_absolute_url" ):
110
+ context = record
111
+ else :
112
+ raise TypeError (
113
+ "for linkify=True, '{}' must have a method get_absolute_url" .format (
114
+ str (context )
115
+ )
112
116
)
113
- )
114
- return context .get_absolute_url ()
117
+ url = context .get_absolute_url ()
118
+
119
+ if self .query :
120
+ url += '?' + urlencode ({
121
+ a : v .resolve (record ) if isinstance (v , Accessor ) else v
122
+ for a , v in self .query .items ()
123
+ })
124
+ if self .fragment :
125
+ url += '#' + self .fragment
126
+
127
+ return url
115
128
116
129
def call_reverse (self , record ):
117
130
"""
@@ -150,6 +163,20 @@ def __call__(self, content, **kwargs):
150
163
151
164
return format_html ("<a {}>{}</a>" , attrs .as_html (), content )
152
165
166
+ @classmethod
167
+ def get_callback (cls , * args , ** kwargs ):
168
+ """
169
+ This method constructs a LinkTransform and returns a callback function suitable as the linkify
170
+ parameter of Column.__init__() This may be used to access features of LinkTransform which aren't
171
+ exposed via linkify dict or tuple linkify values, for example, constructing a url which has both
172
+ positional args AND a query string.
173
+ """
174
+ link_transform = cls (* args , ** kwargs )
175
+
176
+ def callback (record , value , ** kwargs ):
177
+ return link_transform .compose_url (record = record , value = value , ** kwargs )
178
+
179
+ return callback
153
180
154
181
@library .register
155
182
class Column :
@@ -295,8 +322,12 @@ def __init__(
295
322
link_kwargs = None
296
323
if callable (linkify ) or hasattr (self , "get_url" ):
297
324
link_kwargs = dict (url = linkify if callable (linkify ) else self .get_url )
298
- elif isinstance (linkify , (dict , tuple )):
325
+ elif isinstance (linkify , (list , tuple )):
299
326
link_kwargs = dict (reverse_args = linkify )
327
+ elif isinstance (linkify , dict ):
328
+ # specific uppercase keys in linkify are understood to be link_kwargs, and the rest must be reverse_args
329
+ link_kwargs = { name .lower (): linkify .pop (name ) for name in ('QUERY' , 'FRAGMENT' ) if name in linkify }
330
+ link_kwargs ['reverse_args' ] = linkify
300
331
elif linkify is True :
301
332
link_kwargs = dict (accessor = self .accessor )
302
333
0 commit comments