Resolving APIs URL through different namespaces

This commit is contained in:
Marc 2016-01-06 09:56:53 +01:00
parent 060444d89f
commit ca72fa1876

View File

@ -3,8 +3,10 @@ Provide urlresolver functions that return fully qualified URLs or view names
"""
from __future__ import unicode_literals
from django.core.urlresolvers import reverse as django_reverse
from django.conf import urls, settings
from django.core.urlresolvers import reverse as django_reverse, resolve
from django.core.urlresolvers import NoReverseMatch
from django.http import Http404
from django.utils import six
from django.utils.functional import lazy
@ -35,20 +37,60 @@ def preserve_builtin_query_params(url, request=None):
def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
"""
If versioning is being used then we pass any `reverse` calls through
to the versioning scheme instance, so that the resulting URL
can be modified if needed.
to the versioning scheme instance, so that the resulting URL can be modified if needed.
"""
url = None
# Substitute reverse function by scheme's one if versioning enabled
scheme = getattr(request, 'versioning_scheme', None)
if scheme is not None:
def reverse_url(*a, **kw):
try:
url = scheme.reverse(viewname, args, kwargs, request, format, **extra)
return scheme.reverse(*a, **kw)
except NoReverseMatch:
# In case the versioning scheme reversal fails, fallback to the
# default implementation
url = _reverse(viewname, args, kwargs, request, format, **extra)
# In case the versioning scheme reversal fails, fallback to the default implementation
return _reverse(*a, **kw)
else:
url = _reverse(viewname, args, kwargs, request, format, **extra)
reverse_url = _reverse
try:
# Resolving URL normally
url = reverse_url(viewname, args, kwargs, request, format, **extra)
except NoReverseMatch:
if request and ':' not in viewname:
# Retrieving current namespace through request
try:
current_namespace = request.resolver_match.namespace
except AttributeError:
try:
current_namespace = resolve(request.path).namespace
except Http404:
current_namespace = None
if current_namespace:
try:
# Trying to resolve URL with current namespace
viewname_to_try = '{namespace}:{viewname}'.format(namespace=current_namespace, viewname=viewname)
url = reverse_url(viewname_to_try, args, kwargs, request, format, **extra)
except NoReverseMatch:
# Trying to resolve URL with other namespaces
# (Could be wrong if views have the same name in different namespaces)
urlpatterns = urls.import_module(settings.ROOT_URLCONF).urlpatterns
namespaces = [urlpattern.namespace for urlpattern in urlpatterns
if getattr(urlpattern, 'namespace', current_namespace) != current_namespace]
# Remove duplicates but preserve order of elements
from collections import OrderedDict
for namespace in OrderedDict.fromkeys(namespaces):
try:
viewname_to_try = '{namespace}:{viewname}'.format(namespace=namespace, viewname=viewname)
url = reverse_url(viewname_to_try, args, kwargs, request, format, **extra)
break
except NoReverseMatch:
continue
# Raise exception if everything else fails
if not url:
raise
return preserve_builtin_query_params(url, request)