Version 1 (modified by 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, 'admin1', 'admin'), url('^admin2/', include(admin_urls, 'admin2', '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, 'blog', '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.