Version 2 (modified by Florian Apolloner, 10 years ago) ( diff )

--

URLNamespacing

Usecases

The following usecases are those imagined by the author of this document (Florian) and do not necessarily represent the original intentions. That said, they should provide an overview of the available functionality, beeing best pratices or not…

  • Multiple deployments of a single App (like the admin)
  • Prevention of name clashes between view names (This was original not intended)

Analysis of URL namespaces

URL namespaces currently work as follows: Every include() in an URLConf defines an application and an instance namespace. The application namespace is the name of the 'app' ie 'admin' whereas the instance namespace designates the specific deployment of the adminpage, ie 'admin1' or 'admin2':

urlpatterns = [
  url('^admin1/', include(admin_urls, namespace='admin1', app_name='admin'),
  url('^admin2/', include(admin_urls, namespace='admin2', app_name='admin'),
]

which can be resolved the following ways:

>>> reverse('admin:index', current_app='admin1')
'/admin1/'
>>> reverse('admin:index', current_app='admin2')
'/admin2/'
>>> reverse('admin1:index')
'/admin1/'

As can be seen in the examples above, the part before the colon can either act as instance or application name, depending on what was passed in as described by: https://docs.djangoproject.com/en/1.7/topics/http/urls/#reversing-namespaced-urls

To avoid ambiguity in resolving URLs, the current_app approach should be preferred.

Templates don't have the luxury of specifying current_app via the url-tag but can set it on the Context (or request since 1.8). This makes it hard for application developers to provide a list of links to all admin pages (url reversal has to be done in the view) and in general puts current_app into places where it should not be.

Suggested improvements

Provide a way to explicitly pass current_app to the URL tag like for reverse, this could be done as follows:

 {% url 'admin:index' arg1 arg2 current_app='admin1' %}

or

 {% url 'admin:index' on|in 'admin1' arg1 arg2 %}

Both of them are technically speaking backwards incompatible but could be done via an url tag from the future library. While passing current_app to the url tag is a nice and needed feature, it should also be noted that a way to obtain the current app implicitly like currently would be nice to have to avoid passing in the current app on every call. Currently this is done via setting current_app on Context|request. To remove this special casing, the url tag should just lookup the key current_app in the template context (and not on the Context object itself). This would again be backwards incompatible, but a worthwile change.

One of the usecases for URL namespaces is to prevent name collisions, which is usually done as follows:

blog_patterns = [
  url()
]

urlpatterns = [
  url('^blog/', include(blog_patterns, namespace='blog', app_name='blog'),
]

It should be noted that in this case there is technically no benefit over using url names like 'blog_index', but using namespaces from the start allows an easier change later on. Reversing can be done without providing current_app as the default app will get picked anyways. This is, while not an intended usage, a nice feature and should stay.

Note: See TracWiki for help on using the wiki.
Back to Top