Merge pull request #844 from rouge8/hyperlinkedidentityfield-lookup_field

HyperlinkedIdentityField uses `lookup_field` kwarg.
This commit is contained in:
Tom Christie 2013-05-16 10:56:12 -07:00
commit 4ade7fb82c
3 changed files with 61 additions and 6 deletions

View File

@ -196,15 +196,13 @@ Would serialize to a representation like this:
'artist': 'Thom Yorke'
'track_listing': 'http://www.example.com/api/track_list/12/',
}
This field is always read-only.
**Arguments**:
* `view_name` - The view name that should be used as the target of the relationship. **required**.
* `slug_field` - The field on the target that should be used for the lookup. Default is `'slug'`.
* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
* `lookup_field` - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is `'pk'`.
* `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
---

View File

@ -465,10 +465,13 @@ class HyperlinkedIdentityField(Field):
"""
Represents the instance, or a property on the instance, using hyperlinking.
"""
lookup_field = 'pk'
read_only = True
# These are all pending deprecation
pk_url_kwarg = 'pk'
slug_field = 'slug'
slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden
read_only = True
def __init__(self, *args, **kwargs):
# TODO: Make view_name mandatory, and have the
@ -477,6 +480,19 @@ class HyperlinkedIdentityField(Field):
# Optionally the format of the target hyperlink may be specified
self.format = kwargs.pop('format', None)
self.lookup_field = kwargs.pop('lookup_field', self.lookup_field)
# These are pending deprecation
if 'pk_url_kwarg' in kwargs:
msg = 'pk_url_kwarg is pending deprecation. Use lookup_field instead.'
warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
if 'slug_url_kwarg' in kwargs:
msg = 'slug_url_kwarg is pending deprecation. Use lookup_field instead.'
warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
if 'slug_field' in kwargs:
msg = 'slug_field is pending deprecation. Use lookup_field instead.'
warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
self.slug_field = kwargs.pop('slug_field', self.slug_field)
default_slug_kwarg = self.slug_url_kwarg or self.slug_field
self.pk_url_kwarg = kwargs.pop('pk_url_kwarg', self.pk_url_kwarg)
@ -488,7 +504,8 @@ class HyperlinkedIdentityField(Field):
request = self.context.get('request', None)
format = self.context.get('format', None)
view_name = self.view_name or self.parent.opts.view_name
kwargs = {self.pk_url_kwarg: obj.pk}
lookup_field = getattr(obj, self.lookup_field)
kwargs = {self.lookup_field: lookup_field}
if request is None:
warnings.warn("Using `HyperlinkedIdentityField` without including the "

View File

@ -27,6 +27,14 @@ class PhotoSerializer(serializers.Serializer):
return Photo(**attrs)
class AlbumSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='album-detail', lookup_field='title')
class Meta:
model = Album
fields = ('title', 'url')
class BasicList(generics.ListCreateAPIView):
model = BasicModel
model_serializer_class = serializers.HyperlinkedModelSerializer
@ -73,6 +81,8 @@ class PhotoListCreate(generics.ListCreateAPIView):
class AlbumDetail(generics.RetrieveAPIView):
model = Album
serializer_class = AlbumSerializer
lookup_field = 'title'
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
@ -180,6 +190,36 @@ class TestManyToManyHyperlinkedView(TestCase):
self.assertEqual(response.data, self.data[0])
class TestHyperlinkedIdentityFieldLookup(TestCase):
urls = 'rest_framework.tests.hyperlinkedserializers'
def setUp(self):
"""
Create 3 Album instances.
"""
titles = ['foo', 'bar', 'baz']
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`.
"""
for album in Album.objects.all():
request = factory.get('/albums/{0}/'.format(album.title))
response = self.detail_view(request, title=album.title)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, self.data[album.title])
class TestCreateWithForeignKeys(TestCase):
urls = 'rest_framework.tests.hyperlinkedserializers'