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 3576834 commit d8a7e65
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 14 deletions.
9 changes: 9 additions & 0 deletions rest_framework/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ def generic(self, method, path,
return self.request(**r)


# request only provides `resolver_match` from 1.5 onwards.
def get_resolver_match(request):
try:
return request.resolver_match
except AttributeError: # Django < 1.5
from django.core.urlresolvers import resolve
return resolve(request.path_info)


# Markdown is optional
try:
import markdown
Expand Down
12 changes: 11 additions & 1 deletion rest_framework/routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import NoReverseMatch
from rest_framework import views
from rest_framework.compat import OrderedDict
from rest_framework.compat import OrderedDict, get_resolver_match
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.urlpatterns import format_suffix_patterns
Expand Down Expand Up @@ -290,9 +290,19 @@ 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.
"""
resolver_match = get_resolver_match(self.request)
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():
if namespace:
url_name = namespace + ':' + url_name
try:
ret[key] = reverse(
url_name,
Expand Down
32 changes: 32 additions & 0 deletions tests/router_test_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.conf.urls import url, include

from rest_framework import viewsets, mixins, routers

from .test_routers import APIRootTestModel


class APIRootTestViewSet(viewsets.ModelViewSet):
model = APIRootTestModel


class ListlessViewSet(mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
model = APIRootTestModel


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


listless_router = routers.DefaultRouter()
# Avoid conflict with the api/ route.
listless_router.root_view_name = 'listless-api-root'
listless_router.register(r'full', APIRootTestViewSet, 'full')
listless_router.register(r'listless', ListlessViewSet, 'listless')


urlpatterns = [
url(r'^api/', include(router.urls)),
url(r'^namespaced-api/', include(router.urls, namespace='api-namespace')),
url(r'^listless/', include(listless_router.urls)),
]
38 changes: 25 additions & 13 deletions tests/test_routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from django.db import models
from django.test import TestCase
from django.core.exceptions import ImproperlyConfigured
from rest_framework import serializers, viewsets, mixins, permissions
from django.core import urlresolvers
from rest_framework import serializers, viewsets, permissions
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
from rest_framework.routers import SimpleRouter, DefaultRouter
Expand Down Expand Up @@ -307,17 +308,28 @@ def test_list_and_detail_route_decorators(self):
self.assertEqual(route.mapping[method_map], method_name)


class TestRootWithAListlessViewset(TestCase):
def setUp(self):
class NoteViewSet(mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
model = RouterTestModel
# APIRoot
class APIRootTestModel(models.Model):
pass

self.router = DefaultRouter()
self.router.register(r'notes', NoteViewSet)
self.view = self.router.urls[0].callback

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_listless(self):
url = urlresolvers.reverse('listless-api-root')
response = self.client.get(url)
self.assertIn('full', response.data)
self.assertNotIn('listless', response.data)

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 d8a7e65

Please sign in to comment.