From 90f2e26679af8741aaa1c1d0489214062c94765e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 3 Jun 2015 11:00:38 +0100 Subject: [PATCH] Add Hyperlink and rendering in admin style renderer --- rest_framework/relations.py | 25 ++++++++++++++++++- .../rest_framework/admin/list_value.html | 4 ++- .../admin/simple_list_value.html | 1 + rest_framework/templatetags/rest_framework.py | 5 +++- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 rest_framework/templates/rest_framework/admin/simple_list_value.html diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 00a4a2656..93c9be8aa 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -13,6 +13,20 @@ from rest_framework.reverse import reverse from rest_framework.utils import html +class Hyperlink(six.text_type): + """ + A string like object that additionally has an associated name. + We use this for hyperlinked URLs that may render as a named link + in some contexts, or render as a plain URL in others. + """ + def __new__(self, url, name): + ret = six.text_type.__new__(self, url) + ret.name = name + return ret + + is_hyperlink = True + + class PKOnlyObject(object): """ This is a mock object, used for when we only need the pk of the object @@ -203,6 +217,9 @@ class HyperlinkedRelatedField(RelatedField): kwargs = {self.lookup_url_kwarg: lookup_value} return self.reverse(view_name, kwargs=kwargs, request=request, format=format) + def get_name(self, obj): + return str(obj) + def to_internal_value(self, data): request = self.context.get('request', None) try: @@ -261,7 +278,7 @@ class HyperlinkedRelatedField(RelatedField): # Return the hyperlink, or error if incorrectly configured. try: - return self.get_url(value, self.view_name, request, format) + url = self.get_url(value, self.view_name, request, format) except NoReverseMatch: msg = ( 'Could not resolve URL for hyperlinked relationship using ' @@ -271,6 +288,12 @@ class HyperlinkedRelatedField(RelatedField): ) raise ImproperlyConfigured(msg % self.view_name) + if url is None: + return None + + name = self.get_name(value) + return Hyperlink(url, name) + class HyperlinkedIdentityField(HyperlinkedRelatedField): """ diff --git a/rest_framework/templates/rest_framework/admin/list_value.html b/rest_framework/templates/rest_framework/admin/list_value.html index 267bbaa39..cff15635e 100644 --- a/rest_framework/templates/rest_framework/admin/list_value.html +++ b/rest_framework/templates/rest_framework/admin/list_value.html @@ -1,5 +1,5 @@ {% load rest_framework %} - + +{% for item in value %}{% if not forloop.first%}, {% endif %}{{item.name}}{% endfor %} diff --git a/rest_framework/templates/rest_framework/admin/simple_list_value.html b/rest_framework/templates/rest_framework/admin/simple_list_value.html new file mode 100644 index 000000000..2dcaeb62f --- /dev/null +++ b/rest_framework/templates/rest_framework/admin/simple_list_value.html @@ -0,0 +1 @@ +{% for item in value %}{% if not forloop.first%},{% endif %} {% if item.is_hyperlink %}{{item.name}}{% else %}{{ item }}{% endif %}{% endfor %} diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index ef7958eb3..bfbf4c44c 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -111,7 +111,10 @@ def format_value(value): if isinstance(value, (int, float, decimal.Decimal, bool, type(None))): return mark_safe('%s' % value) elif isinstance(value, list): - template = loader.get_template('rest_framework/admin/list_value.html') + if any([isinstance(item, (list, dict)) for item in value]): + template = loader.get_template('rest_framework/admin/list_value.html') + else: + template = loader.get_template('rest_framework/admin/simple_list_value.html') context = Context({'value': value}) return template.render(context) elif isinstance(value, dict):