Opened 15 years ago
Closed 10 years ago
#11642 closed New feature (fixed)
Specify default namespace in urls.py
Reported by: | Tai Lee | Owned by: | Amirouche |
---|---|---|---|
Component: | Core (URLs) | Version: | 1.1 |
Severity: | Normal | Keywords: | url namespace default |
Cc: | amirouche.boubekki@…, Florian Apolloner | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | yes |
Needs tests: | yes | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
The new URL namespace feature is great, but could be made a little easier to use by allowing a default namespace to be defined as a variable in the urls module being included (e.g. namespace
). This could be looked up by Django automatically if no namespace is specified when the urls module is included, in the same way that urlpatterns
is looked up.
In myapp/urls.py
:
namespace = 'myapp' urlpatterns('myapp', url('^$', 'index', name='index'), )
In myproject/urls.py
:
urlpatterns('', url(r'^myapp/$', include('myapp.urls')), )
In your templates:
{% url myapp:index %}
The benefit here is that users will not need to specify a namespace for every app in their urls module to avoid clashes with commonly named urls (e.g. "index"), unless they are deploying multiple instances of the same app, which I would have thought is the less common case.
At the moment I believe the only way to specify a default namespace (like the admin
app does) is to define a three item tuple somewhere in myapp
which contains urlpatterns
from myapp.urls
plus app and instance namespaces. But this can't be referenced by a simple string like the urls module can, it must be imported directly before being used. It also seems a little messy and counter-intuitive asking users to import and include myapp.urls.namespace
or myapp.urls_namespace
or something similar, instead of just importing or referencing the urls module.
Attachments (1)
Change History (14)
comment:1 by , 15 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 15 years ago
I'm slightly against the concept of forcing or even encouraging namespace use just to avoid clashes in poorly named URL patterns. We already recommend making URL pattern names unique. They are top-level names. Just like your Python module names have to be unique amongst all modules on the Python path, etc. Coming up with unique names isn't even that hard.
So the primary motivation behind this ticket is a bit suspect.
comment:3 by , 15 years ago
@malcolm - I agree completely that this isn't the solution for making 'index' a unique name. I'm almost starting to regret using the term "namespace", since it seems to be encouraging the use of namespaces to tell app1.index from app2.index, which (as you well know) wasn't the intention.
My motivation for accepting this ticket was to provide an analog for the way dynamic url deployments (e.g., what admin uses) specify default application namespaces.
Consider contrib.admin. When you deploy admin using include(admin.site.urls), the admin app provides a triple that gives you the instance name and application namespace to use. In that way, the application is designed to be deployed multiple times, as it's impossible to deploy the app without a namespace.
As a counterpoint, consider contrib.comments. This uses a traditional urls module for deployment, so it means if you want to use an application level namespace, you need to include('comments.urls', namespace='foo', app_name='comments'). There is no analog for getting the application name as a default during deployment.
My ideal picture is that if an application developer knows a priori that their application is a candidate for multiple deployment, then they could specify an application namespace. include('myapp.urls') would deploy an instance of the app with the default (i.e. == app) namespace - just like admin does. include('myapp.urls', namespace='foo') would deploy an instance of the app with a specific name.
It's not a major problem - just an inconsistency that I think is worth looking at. If we can't find a way to provide this capability elegantly and unambiguously, then I'll be the first to throw the idea overboard.
comment:4 by , 15 years ago
I'm not sure why there is resistance to using namespaces to avoid URL name clashes between different apps, as well as allowing multiple deployments of the same app. Both are useful. An app developer should only need to worry about named URLs being unique within their own app because this is all they have control over, and Django provides a way for users to resolve app name conflicts if they occur.
Looking at the admin app as a real world example, it's probably far more common that people only deploy one instance, yet it provides default app and instance names, and has a URL named simply "index". All apps should be able to follow this example, without having to configure and import a dynamic urlconf like the admin app does.
I've written up a patch that behaves according to Russell's ideal picture above. The app developer can specify a default app name by assigning a string to the app_name
variable in the app's urlconf module. This is something of a "magic" variable tied to the urlconf (much like urlpatterns
), but after looking at a few alternatives, I think it is still the best option as it is under the control of the app developer, and doesn't require anything different or special from the user when importing the urlconf module the same as any other app. Then include('myapp.urls')
will use myapp.urls.app_name
(if it is set) as the default app name. The user can always override the app/instance names with the namespace
and app_name
arguments to include()
.
The docs regarding URL namespaces say that "the default application instance is the instance that has an instance namespace matching the application namespace", so I've also modified include()
to use app_name
(specified or default) as the default instance name.
The current include()
function will raise an ImproperlyConfigured
exception if a tuple is passed in as arg
*and* namespace
is also specified. Although strangely, no exception is raised if app_name
is specified, and this is silently discarded. There appears to be an assumption that only dynamic modules that provide a namespace will ever pass a tuple to include()
(of which I'm only aware of one, the admin app), and these should be configured to use a different namespace elsewhere. But this isn't reflected in the docs about URL namespacing which lists a tuple as second option to specify namespaces.
I think that any values passed to include()
as namespace
or app_name
should always override the defaults (obtained from the tuple or urlconf module), and when using a dynamic module that provides a namespace, users shouldn't be trying to override it anyway. I've removed this exception in my patch and made include()
behave in the same way whether a tuple or string or urlconf module is passed in. For a tuple, the defaults are taken from the 2nd and 3rd items. For a string or urlconf module, the defaults are taken from the app_name
attribute of the urlconf module. For both, app_name
is the default namespace
.
by , 15 years ago
Attachment: | 11642-default-namespace-r11413.diff added |
---|
Get default app_name
from urlconf module.
comment:5 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → New feature |
comment:6 by , 13 years ago
Easy pickings: | unset |
---|---|
UI/UX: | unset |
why did this stagnate? EDIT: did not unset UI/UX or Easy pickings on purpose.
comment:7 by , 12 years ago
Component: | Core (Other) → Core (URLs) |
---|
comment:8 by , 12 years ago
Cc: | added |
---|---|
Needs documentation: | set |
Needs tests: | set |
Owner: | changed from | to
Patch needs improvement: | set |
Status: | new → assigned |
deleted
comment:9 by , 12 years ago
Status: | assigned → new |
---|
comment:11 by , 10 years ago
I think the patch from mrmachine is sensible. In a nutshell: specifying app_name
on the url module should set the default app_name
and namespace
and everything in include()
should override this default.
comment:12 by , 10 years ago
Cc: | added |
---|
There's the start of an idea here, but it's not fully formed. For starters, there isn't a single concept of a 'namespace' - there's the application namespace and the instance namespace. What you refer to as the "default" namespace is the application namespace.
Essentially, it sounds like you're proposing that include('myapp.urls', namespace='foo', app_name='bar') can be made easier for the case where an application knows it can provide a namespace. I agree with this. However, it isn't quite as simple as you describe. By definition, you can't define the instance namespace in the way you describe. However, you could define the application namespace in this way.
There are some issues that need to be resolved here - for instance:
I'll mark this as accepted in principle - but there is some design work that still needs to be done. If you can resolve what happens in the edge cases, this shouldn't be too hard to implement (patches welcome).