Skip to content

Commit

Permalink
Add support for namespaces in APIRoot.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rocky Meza committed Dec 25, 2014
1 parent e6041f9 commit eb0b5ca
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 1 deletion.
20 changes: 19 additions & 1 deletion rest_framework/routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from collections import namedtuple
from django.conf.urls import patterns, url
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import NoReverseMatch
from django.core.urlresolvers import NoReverseMatch, resolve, Resolver404
from rest_framework import views
from rest_framework.compat import OrderedDict
from rest_framework.response import Response
Expand Down Expand Up @@ -290,9 +290,27 @@ def get_api_root_view(self):
class APIRoot(views.APIView):
_ignore_model_permissions = True

def get_namespace(self):
"""
Attempt to retrieve the namespace of the current router.
"""
try:
# It appears that resolver_match is available on the
# request object itself, but it isn't available during
# tests.
resolver_match = resolve(self.request.path_info)
except Resolver404:
# Because we are resolving the URL for the current request,
# this should never fail, but it does during tests.
return None
else:
return resolver_match.namespace

def get(self, request, *args, **kwargs):
ret = OrderedDict()
namespace = self.get_namespace()
for key, url_name in api_root_dict.items():
url_name = ':'.join(filter(bool, (namespace, url_name)))
try:
ret[key] = reverse(
url_name,
Expand Down
32 changes: 32 additions & 0 deletions tests/namespaced_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.conf.urls import url, include
from django.db import models

from rest_framework import serializers, viewsets, routers


class NamespacedRouterTestModel(models.Model):
uuid = models.CharField(max_length=20)
text = models.CharField(max_length=200)


class NoteSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='api-namespace:routertestmodel-detail', lookup_field='uuid')

class Meta:
model = NamespacedRouterTestModel
fields = ('url', 'uuid', 'text')


class NoteViewSet(viewsets.ModelViewSet):
queryset = NamespacedRouterTestModel.objects.all()
serializer_class = NoteSerializer
lookup_field = 'uuid'

router = routers.DefaultRouter()

router.register(r'note', NoteViewSet)


urlpatterns = [
url('^namespaced-api/', include(router.urls, namespace='api-namespace')),
]
11 changes: 11 additions & 0 deletions tests/test_routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.db import models
from django.test import TestCase
from django.core.exceptions import ImproperlyConfigured
from django.core import urlresolvers
from rest_framework import serializers, viewsets, mixins, permissions
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
Expand Down Expand Up @@ -321,3 +322,13 @@ def test_api_root(self):
request = factory.get('/')
response = self.view(request)
self.assertEqual(response.data, {})


class TestRootWithNamespacedURLs(TestCase):
urls = 'tests.namespaced_urls'

def test_api_root_contains_routes(self):
url = urlresolvers.reverse('api-namespace:api-root')
response = self.client.get(url)
self.assertIn('note', response.data)
self.assertEqual(response.data['note'], 'http://testserver/namespaced-api/note/')

0 comments on commit eb0b5ca

Please sign in to comment.