Opened 15 years ago
Closed 9 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 |
tl;dr:
- +1 for the current feature request
- make it possible to have a default application namespace everytime
Todo:
- maybe update for master
- default application namespace everytime
- more test
- more documentation
This would be nice and will IMO allow to simplify the url namespace thing while still keeping the mechanics for complex (and a bit weird setups) possible and for most usecases, people will say «Yay! it's actually what I need!».
I did not understand the point of «application_namespace» until I wrote the following paragraph:
Application namespace is useless inside the application itself, since application_ns:index will always resolve to current_app:index in this case, application_ns:index is equivalent to index. There is a case where «index» can be something else when you are inside another application, url patterns of application B, included in url patterns of application A, and have another view named «index», then the only way inside application B to get the index of application A in a *generic way* is to use the application A application namespace. This can be achieve otherwise, and I think that what is still used by people, you namespace the url name of so that you never have the same urls names something like «app-a-index» or «app-b-index» or better use semantic url names instead of generic naming.
Using application namespace outside of the application is weird at best, I did not find a useful usecase for it, except maybe if an application C, is included in a project and expects application A to exists then getting reverse
work needs the «default application for application namespace» mechanics and the fallback mechanics.
Basically what OP says and with which I agree, is that most of the time (not to say all the time) the guy or gal writring app.urls knows which application_namespace to use for the application so including it in the urls.py makes sens. I will go further and say that namespace which becomes application_namespace should has a default of the application package name. Like @russellm points Python package names are most of the time unique among Python/Django and happens to be most of the time what we need. Allowing for providing another application_namespace introduce the replaceable application pattern, for instance: to allow the django favorites application market to flourish no one use the same package name (which I think allows for them to all be on PyPi) but they all agree to use the same url names, the first is named «django-kingking-favorites» & «kingking» as package name, it doesn't support ajax, so another application exists which implements the same «url scheme» its package is «princess», it's a drop-in replacement of «kingking». If they both use the default application namespace induced by the package name it will be possible to replace one app by another but it will be more difficult (rebuild the favorite application urls inside the project urls for instance).
We cannot get the application package name right everytime (if the patterns are somewhere inside another package inside the application package) to avoid any complex code (!) I will use the urls.py package name, the author will be able to override this default with namespace variable.
Saying -1 or 0 with the argument «this can be done with namespace url names» is not an argument, getting the «application namespace» feature is already useless given namespaced url names.
I'm not sure about the «namespace» naming, maybe «application_namespace» is better, what do you think ?
Here is a usecase, for overriding the application namespace provided by the application author outside the application: There is a clash between several applications that use the same app namespace, but not the same url name schemes aka. they are not replaceable application this should be done with care since it can break the current app which might be using the application namespace... Like it's said earlier this is unlikely to happen.
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).