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 %} -<table class="table table-striped"> +<!-- <table class="table table-striped"> <tbody> {% for item in value %} <tr> @@ -9,3 +9,5 @@ {% endfor %} </tbody> </table> + --> +{% for item in value %}{% if not forloop.first%}, {% endif %}<a href="{{ item }}">{{item.name}}</a>{% 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 %}<a href="{{ item }}">{{item.name}}</a>{% 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('<code>%s</code>' % 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):