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 27, 2014
1 parent e6041f9 commit b36a4fd
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 1 deletion.
19 changes: 18 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,26 @@ 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:
resolver_match = self.request.resolver_match
except AttributeError: # Either Django < 1.5 or in tests
try:
resolver_match = resolve(self.request.path_info)
except Resolver404: # We are in the tests
return None
if resolver_match is not None: # Django > 1.5 and in tests
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():
# From django.core.urlresolvers.ResolverMatch.view_name
url_name = ':'.join(filter(bool, (namespace, url_name)))
try:
ret[key] = reverse(
url_name,
Expand Down
5 changes: 5 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class FilterableItem(BaseFilterableItem):
date = models.DateField()


# APIRoot
class APIRootTestModel(models.Model):
pass


# Models for relations tests
# ManyToMany
class ManyToManyTarget(RESTFrameworkModel):
Expand Down
19 changes: 19 additions & 0 deletions tests/router_test_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.conf.urls import url, include

from rest_framework import viewsets, routers

from .models import APIRootTestModel


class APIRootTestViewSet(viewsets.ModelViewSet):
model = APIRootTestModel


router = routers.DefaultRouter()
router.register(r'test-model', APIRootTestViewSet)


urlpatterns = [
url('^api/', include(router.urls)),
url('^namespaced-api/', include(router.urls, namespace='api-namespace')),
]
17 changes: 17 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,19 @@ def test_api_root(self):
request = factory.get('/')
response = self.view(request)
self.assertEqual(response.data, {})


class TestAPIRootView(TestCase):
urls = 'tests.router_test_urls'

def test_normal_api_root_contains_routes(self):
url = urlresolvers.reverse('api-root')
response = self.client.get(url)
self.assertIn('test-model', response.data)
self.assertEqual(response.data['test-model'], 'http://testserver/api/test-model/')

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

0 comments on commit b36a4fd

Please sign in to comment.