mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-30 18:09:59 +03:00
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:
parent
02b29267ac
commit
77c17b90e2
|
@ -514,12 +514,20 @@ class HyperlinkedIdentityField(Field):
|
||||||
|
|
||||||
super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
|
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):
|
def field_to_native(self, obj, field_name):
|
||||||
request = self.context.get('request', None)
|
request = self.context.get('request', None)
|
||||||
format = self.context.get('format', None)
|
format = self.context.get('format', None)
|
||||||
view_name = self.view_name or self.parent.opts.view_name
|
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:
|
if request is None:
|
||||||
warnings.warn("Using `HyperlinkedIdentityField` without including the "
|
warnings.warn("Using `HyperlinkedIdentityField` without including the "
|
||||||
|
|
|
@ -35,6 +35,15 @@ class AlbumSerializer(serializers.ModelSerializer):
|
||||||
fields = ('title', 'url')
|
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):
|
class BasicList(generics.ListCreateAPIView):
|
||||||
model = BasicModel
|
model = BasicModel
|
||||||
model_serializer_class = serializers.HyperlinkedModelSerializer
|
model_serializer_class = serializers.HyperlinkedModelSerializer
|
||||||
|
@ -85,6 +94,10 @@ class AlbumDetail(generics.RetrieveAPIView):
|
||||||
lookup_field = 'title'
|
lookup_field = 'title'
|
||||||
|
|
||||||
|
|
||||||
|
class UpperCaseAlbumDetail(AlbumDetail):
|
||||||
|
serializer_class = UpperCaseAlbumSerializer
|
||||||
|
|
||||||
|
|
||||||
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
|
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
model = OptionalRelationModel
|
model = OptionalRelationModel
|
||||||
model_serializer_class = serializers.HyperlinkedModelSerializer
|
model_serializer_class = serializers.HyperlinkedModelSerializer
|
||||||
|
@ -201,23 +214,41 @@ class TestHyperlinkedIdentityFieldLookup(TestCase):
|
||||||
for title in titles:
|
for title in titles:
|
||||||
album = Album(title=title)
|
album = Album(title=title)
|
||||||
album.save()
|
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):
|
def test_lookup_field(self):
|
||||||
"""
|
"""
|
||||||
GET requests to AlbumDetail view should return serialized Albums
|
GET requests to AlbumDetail view should return serialized Albums
|
||||||
with a url field keyed by `title`.
|
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():
|
for album in Album.objects.all():
|
||||||
request = factory.get('/albums/{0}/'.format(album.title))
|
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.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):
|
class TestCreateWithForeignKeys(TestCase):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user