Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Handle reversal of non-API view_name in HyperLinkedRelatedField
  • Loading branch information
delinhabit committed Mar 19, 2015
commit 90280a343746f662ac2e7da4844828a61253c77d
12 changes: 11 additions & 1 deletion rest_framework/versioning.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# coding: utf-8
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import NoReverseMatch
from rest_framework import exceptions
from rest_framework.compat import unicode_http_header
from rest_framework.reverse import _reverse
Expand Down Expand Up @@ -122,7 +123,16 @@ def determine_version(self, request, *args, **kwargs):

def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request.version is not None:
viewname = self.get_versioned_viewname(viewname, request)
versioned_viewname = self.get_versioned_viewname(viewname, request)
try:
return super(NamespaceVersioning, self).reverse(
versioned_viewname, args, kwargs, request, format, **extra
)
except NoReverseMatch:
# If the versioned viewname lookup fails, fallback to the
# default reversal, since it may be a non-API view
pass

return super(NamespaceVersioning, self).reverse(
viewname, args, kwargs, request, format, **extra
)
Expand Down
44 changes: 43 additions & 1 deletion tests/test_versioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from rest_framework.reverse import reverse
from rest_framework.test import APIRequestFactory, APITestCase
from rest_framework.versioning import NamespaceVersioning
from rest_framework.relations import PKOnlyObject
import pytest


Expand Down Expand Up @@ -234,7 +235,7 @@ class FakeResolverMatch:

class TestHyperlinkedRelatedField(UsingURLPatterns, APITestCase):
included = [
url(r'^namespaced/(?P<pk>\d+)/$', dummy_view, name='namespaced'),
url(r'^namespaced/(?P<pk>\d+)/$', dummy_pk_view, name='namespaced'),
]

urlpatterns = [
Expand Down Expand Up @@ -262,3 +263,44 @@ def test_bug_2489(self):
assert self.field.to_internal_value('/v1/namespaced/3/') == 'object 3'
with pytest.raises(serializers.ValidationError):
self.field.to_internal_value('/v2/namespaced/3/')


class TestNamespaceVersioningHyperlinkedRelatedFieldScheme(UsingURLPatterns, APITestCase):
included = [
url(r'^namespaced/(?P<pk>\d+)/$', dummy_pk_view, name='namespaced'),
]

urlpatterns = [
url(r'^v1/', include(included, namespace='v1')),
url(r'^v2/', include(included, namespace='v2')),
url(r'^non-api/(?P<pk>\d+)/$', dummy_pk_view, name='non-api-view')
]

def _create_field(self, view_name, version):
request = factory.get("/")
request.versioning_scheme = NamespaceVersioning()
request.version = version

field = serializers.HyperlinkedRelatedField(
view_name=view_name,
read_only=True)
field._context = {'request': request}
return field

def test_api_url_is_properly_reversed_with_v1(self):
field = self._create_field('namespaced', 'v1')
assert field.to_representation(PKOnlyObject(3)) == 'http://testserver/v1/namespaced/3/'

def test_api_url_is_properly_reversed_with_v2(self):
field = self._create_field('namespaced', 'v2')
assert field.to_representation(PKOnlyObject(5)) == 'http://testserver/v2/namespaced/5/'

def test_non_api_url_is_properly_reversed_regardless_of_the_version(self):
"""
Regression test for #2711
"""
field = self._create_field('non-api-view', 'v1')
assert field.to_representation(PKOnlyObject(10)) == 'http://testserver/non-api/10/'

field = self._create_field('non-api-view', 'v2')
assert field.to_representation(PKOnlyObject(10)) == 'http://testserver/non-api/10/'