Get HyperlinkedIdentityField value via method call.

Add the ability to get an HyperlinkedIdentityField value from a method call
rather than a straight attribute lookup.  This allows subclasses to transform
the value returned if needed.
This commit is contained in:
Brian Zambrano 2013-05-23 19:56:56 -07:00
parent 02b29267ac
commit 77c17b90e2
2 changed files with 49 additions and 10 deletions

View File

@ -514,12 +514,20 @@ class HyperlinkedIdentityField(Field):
super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
def get_lookup_value(self, obj):
"""Return the value of the lookup field. Subclasses can override this
for custom behavior which is more complex than returning a pk or other
named attribute of the object.
"""
return getattr(obj, self.lookup_field)
def field_to_native(self, obj, field_name):
request = self.context.get('request', None)
format = self.context.get('format', None)
view_name = self.view_name or self.parent.opts.view_name
lookup_field = getattr(obj, self.lookup_field)
kwargs = {self.lookup_field: lookup_field}
kwargs = {self.lookup_field: self.get_lookup_value(obj)}
if request is None:
warnings.warn("Using `HyperlinkedIdentityField` without including the "

View File

@ -35,6 +35,15 @@ class AlbumSerializer(serializers.ModelSerializer):
fields = ('title', 'url')
class UpperCaseTitleField(serializers.HyperlinkedIdentityField):
def get_lookup_value(self, obj):
return obj.title.upper()
class UpperCaseAlbumSerializer(AlbumSerializer):
url = UpperCaseTitleField(view_name='album-detail', lookup_field='title')
class BasicList(generics.ListCreateAPIView):
model = BasicModel
model_serializer_class = serializers.HyperlinkedModelSerializer
@ -85,6 +94,10 @@ class AlbumDetail(generics.RetrieveAPIView):
lookup_field = 'title'
class UpperCaseAlbumDetail(AlbumDetail):
serializer_class = UpperCaseAlbumSerializer
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
model = OptionalRelationModel
model_serializer_class = serializers.HyperlinkedModelSerializer
@ -201,23 +214,41 @@ class TestHyperlinkedIdentityFieldLookup(TestCase):
for title in titles:
album = Album(title=title)
album.save()
self.detail_view = AlbumDetail.as_view()
self.data = {
'foo': {'title': 'foo', 'url': 'http://testserver/albums/foo/'},
'bar': {'title': 'bar', 'url': 'http://testserver/albums/bar/'},
'baz': {'title': 'baz', 'url': 'http://testserver/albums/baz/'}
}
def test_lookup_field(self):
"""
GET requests to AlbumDetail view should return serialized Albums
with a url field keyed by `title`.
"""
detail_view = AlbumDetail.as_view()
data = {
'foo': {'title': 'foo', 'url': 'http://testserver/albums/foo/'},
'bar': {'title': 'bar', 'url': 'http://testserver/albums/bar/'},
'baz': {'title': 'baz', 'url': 'http://testserver/albums/baz/'}
}
for album in Album.objects.all():
request = factory.get('/albums/{0}/'.format(album.title))
response = self.detail_view(request, title=album.title)
response = detail_view(request, title=album.title)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, self.data[album.title])
self.assertEqual(response.data, data[album.title])
def test_lookup_field_function(self):
"""
GET requests to UpperCaseAlbumDetail which runs with a custom
HyperlinkedIdentityField, tranforming the title to uppercase via an
overridden method.
"""
uppercase_view = UpperCaseAlbumDetail.as_view()
data = {
'foo': {'title': 'foo', 'url': 'http://testserver/albums/FOO/'},
'bar': {'title': 'bar', 'url': 'http://testserver/albums/BAR/'},
'baz': {'title': 'baz', 'url': 'http://testserver/albums/BAZ/'}
}
for album in Album.objects.all():
request = factory.get('/albums/{0}/'.format(album.title))
response = uppercase_view(request, title=album.title)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, data[album.title])
class TestCreateWithForeignKeys(TestCase):