drf-extensions
drf-extensions copied to clipboard
DefaultRouterExtensible
The issue right now is that if there are multiple applications within the same Django project, the root api view does not pull in all end points. This helps to solve that problem.
What do you think of pulling in something like: https://github.com/tomchristie/django-rest-framework/pull/2001 to drf-extensions?
The implementation would look something like:
class DefaultRouterExtensible(DefaultRouter):
def __init__(self, require_authenticated=True, include_root_view=True, *args, **kwargs):
super(DefaultRouterExtensible, self).__init__(*args, **kwargs)
self.require_authenticated = require_authenticated
self.include_root_view = include_root_view
def get_api_root_dict(self):
api_root_dict = OrderedDict()
list_name = self.routes[0].name
for prefix, viewset, basename in self.registry:
api_root_dict[prefix] = list_name.format(basename=basename)
return api_root_dict
def get_api_root_view(self):
"""
Return a view to use as the API root.
"""
api_root_dict = self.get_api_root_dict()
class APIRoot(views.APIView):
permission_classes = (permissions.IsAuthenticated, ) if self.require_authenticated else ()
_ignore_model_permissions = True
def get(self, request, *args, **kwargs):
ret = OrderedDict()
namespace = get_resolver_match(request).namespace
for key, url_name in api_root_dict.items():
if namespace:
url_name = namespace + ':' + url_name
try:
ret[key] = reverse(
url_name,
request=request,
format=kwargs.get('format', None)
)
except NoReverseMatch: # pragma: no cover
# Don't bail out if eg. no list routes exist, only detail routes.
continue
return Response(ret)
return APIRoot.as_view()
class DefaultRouterAddItem(DefaultRouterExtensible):
def __init__(self, *args, **kwargs):
super(DefaultRouterAddItem, self).__init__(*args, **kwargs)
self._additional_api_root_dict = {}
def add_routes_to_root(self, route_dict):
duplicate_routes = set(self._additional_api_root_dict.keys()) & set(route_dict.keys())
# Make sure we are not attempting to add a route that already exists
assert not duplicate_routes, duplicate_routes
self._additional_api_root_dict.update(route_dict)
def get_api_root_dict(self):
ret = super(DefaultRouterAddItem, self).get_api_root_dict()
for k, v in self._additional_api_root_dict.iteritems():
ret[k] = v
return ret
I believe that extensible DefaultRoute should be in core of DRF.
Unless @tomchristie has changed his mind since the last discussion, that won't be happening.
It wont. Routers and viewsets are already too complicated, and there's no reason variations on them can't instead be supported in third party packages.
class ContainerRouter(DefaultRouter): def register_router(self, router): self.registry.extend(router.registry)
router = ContainerRouter() router.register_router(router1) router.register_router(router2)
urlpatterns = [ url(r'^api/', include(router.urls)), ]