Skip to content

Commit

Permalink
Add query string and fragment identifier capability to linkify.
Browse files Browse the repository at this point in the history
  • Loading branch information
benmehlman committed Nov 6, 2019
1 parent 82411ec commit e14b529
Showing 1 changed file with 47 additions and 16 deletions.
63 changes: 47 additions & 16 deletions django_tables2/columns/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections import OrderedDict
from itertools import islice
from urllib.parse import urlencode

from django.core.exceptions import ImproperlyConfigured
from django.urls import reverse
Expand Down Expand Up @@ -65,7 +66,7 @@ class LinkTransform:
accessor = None
attrs = None

def __init__(self, url=None, accessor=None, attrs=None, reverse_args=None):
def __init__(self, url=None, accessor=None, attrs=None, reverse_args=None, query=None, fragment=None):
"""
arguments:
url (callable): If supplied, the result of this callable will be used as ``href`` attribute.
Expand All @@ -79,6 +80,8 @@ def __init__(self, url=None, accessor=None, attrs=None, reverse_args=None):
self.url = url
self.attrs = attrs
self.accessor = accessor
self.query = query
self.fragment = fragment

if isinstance(reverse_args, (list, tuple)):
viewname, args = reverse_args
Expand All @@ -95,23 +98,33 @@ def compose_url(self, **kwargs):
record = kwargs["record"]

if self.reverse_args.get("viewname", None) is not None:
return self.call_reverse(record=record)

if bound_column is None and self.accessor is None:
accessor = Accessor("")
url = self.call_reverse(record=record)
else:
accessor = Accessor(self.accessor if self.accessor is not None else bound_column.name)
context = accessor.resolve(record)
if not hasattr(context, "get_absolute_url"):
if hasattr(record, "get_absolute_url"):
context = record
if bound_column is None and self.accessor is None:
accessor = Accessor("")
else:
raise TypeError(
"for linkify=True, '{}' must have a method get_absolute_url".format(
str(context)
accessor = Accessor(self.accessor if self.accessor is not None else bound_column.name)
context = accessor.resolve(record)
if not hasattr(context, "get_absolute_url"):
if hasattr(record, "get_absolute_url"):
context = record
else:
raise TypeError(
"for linkify=True, '{}' must have a method get_absolute_url".format(
str(context)
)
)
)
return context.get_absolute_url()
url = context.get_absolute_url()

if self.query:
url += '?' + urlencode({
a: v.resolve(record) if isinstance(v, Accessor) else v
for a, v in self.query.items()
})
if self.fragment:
url += '#' + self.fragment

return url

def call_reverse(self, record):
"""
Expand Down Expand Up @@ -150,6 +163,20 @@ def __call__(self, content, **kwargs):

return format_html("<a {}>{}</a>", attrs.as_html(), content)

@classmethod
def get_callback(cls, *args, **kwargs):
"""
This method constructs a LinkTransform and returns a callback function suitable as the linkify
parameter of Column.__init__() This may be used to access features of LinkTransform which aren't
exposed via linkify dict or tuple linkify values, for example, constructing a url which has both
positional args AND a query string.
"""
link_transform = cls(*args, **kwargs)

def callback(record, value, **kwargs):
return link_transform.compose_url(record=record, value=value, **kwargs)

return callback

@library.register
class Column:
Expand Down Expand Up @@ -295,8 +322,12 @@ def __init__(
link_kwargs = None
if callable(linkify) or hasattr(self, "get_url"):
link_kwargs = dict(url=linkify if callable(linkify) else self.get_url)
elif isinstance(linkify, (dict, tuple)):
elif isinstance(linkify, (list, tuple)):
link_kwargs = dict(reverse_args=linkify)
elif isinstance(linkify, dict):
# specific uppercase keys in linkify are understood to be link_kwargs, and the rest must be reverse_args
link_kwargs = { name.lower(): linkify.pop(name) for name in ('QUERY', 'FRAGMENT') if name in linkify }
link_kwargs['reverse_args'] = linkify
elif linkify is True:
link_kwargs = dict(accessor=self.accessor)

Expand Down

0 comments on commit e14b529

Please sign in to comment.