This commit is contained in:
cknave 2016-08-28 08:00:07 +00:00 committed by GitHub
commit ea5a07d213
2 changed files with 27 additions and 3 deletions

View File

@ -35,15 +35,27 @@ class Hyperlink(six.text_type):
A string like object that additionally has an associated name. A string like object that additionally has an associated name.
We use this for hyperlinked URLs that may render as a named link We use this for hyperlinked URLs that may render as a named link
in some contexts, or render as a plain URL in others. in some contexts, or render as a plain URL in others.
If name is callable, it will be called when the name property is
accessed.
""" """
def __new__(self, url, name): def __new__(self, url, name):
ret = six.text_type.__new__(self, url) ret = six.text_type.__new__(self, url)
ret.name = name if callable(name):
ret._name_callable = name
else:
ret.name = name
return ret return ret
def __getnewargs__(self): def __getnewargs__(self):
return(str(self), self.name,) return(str(self), self.name,)
def __getattr__(self, key):
if key == 'name' and hasattr(self, '_name_callable'):
f = getattr(self, '_name_callable')
return f()
raise AttributeError
is_hyperlink = True is_hyperlink = True
@ -378,8 +390,8 @@ class HyperlinkedRelatedField(RelatedField):
if url is None: if url is None:
return None return None
name = self.get_name(value) name_getter = lambda: self.get_name(value)
return Hyperlink(url, name) return Hyperlink(url, name_getter)
class HyperlinkedIdentityField(HyperlinkedRelatedField): class HyperlinkedIdentityField(HyperlinkedRelatedField):

View File

@ -98,6 +98,11 @@ class TestHyperlinkedRelatedField(APISimpleTestCase):
representation = self.field.to_representation(MockObject(pk='')) representation = self.field.to_representation(MockObject(pk=''))
assert representation is None assert representation is None
def test_representation_does_not_call_get_name(self):
self.field.get_name = lambda _: pytest.fail(
"HyperlinkedRelatedField.get_name() called eagerly")
self.field.to_representation(MockObject(pk=1))
class TestHyperlinkedIdentityField(APISimpleTestCase): class TestHyperlinkedIdentityField(APISimpleTestCase):
def setUp(self): def setUp(self):
@ -233,9 +238,16 @@ class TestManyRelatedField(APISimpleTestCase):
class TestHyperlink: class TestHyperlink:
def setup(self): def setup(self):
self.default_hyperlink = serializers.Hyperlink('http://example.com', 'test') self.default_hyperlink = serializers.Hyperlink('http://example.com', 'test')
self.callable_hyperlink = serializers.Hyperlink('http://example.com', lambda: 'called')
def test_can_be_pickled(self): def test_can_be_pickled(self):
import pickle import pickle
upkled = pickle.loads(pickle.dumps(self.default_hyperlink)) upkled = pickle.loads(pickle.dumps(self.default_hyperlink))
assert upkled == self.default_hyperlink assert upkled == self.default_hyperlink
assert upkled.name == self.default_hyperlink.name assert upkled.name == self.default_hyperlink.name
def test_simple_name_property(self):
assert 'test' == self.default_hyperlink.name
def test_callable_name_property(self):
assert 'called' == self.callable_hyperlink.name