What's the question?
==================
A project may be separated into many pieces of apps, and these apps
can be move to other places or reused, so the url of the apps maybe
changed, and how to easy deal with such change? And we also need to
assume that only apps which have url prefix need to think about. So a
app and some function of it can be see as:
http://domain/app_prefix/function/parameter
So we want to think about if the app_pefix can be easily changed or remapped.
And there are maybe three places we need to think about:
1. urls.py
2. views
3. template
How to solved it?
==============
It's just my opinion, welcome to disscuss.
1. Define app's prefix in someplaces
------------------------------------------------------------
There are many places:
a) in INSTALLED_APPS
INSTALLED_APPS = (
('apps.profile', 'profile'),
('apps.woodlog', 'blog'),
('apps.rss', 'rss'),
}
But in this way, how to easy get the apps name?
b) define a new dict in settings.py or other place:
APPS_PREFIX = (
('profile', 'profile'),
('blog', 'blog'),
('rss', 'rss'),
)
2. Remap rule
---------------------------
We can define a special string format in urls, for example, there are
many candidates:
a) '$blog/username/2006/04/04/2.html'
b) '%(blog)s/username/2006/04/04/2.html'
c) something else
So if we define a '$blog' or '%(blog)s' in urls.py or
HttpResponseRedirect or some places relative to URL, the remap rule
will be enabled.
First the remap machanism will find if there is a $ string or %()
string, if there is, it'll auto check the APPS_PREFIX, and find if
there is a match string, if it does so, replace the $ string or %()
string, and if it does not, replace $string or %(string)s be string.
So if the develop didn't define APPS_PREFIX that's ok.
In template, we can provide a default tag to do this definition:
<a href="{% urlmap '$blog' %}/username/2006/04/04/2.html'>{{ object.title }}</a>
I don't know if the appoach is simple enough, and if we do like this,
some things need to changed, for example the process of urlpattern,
HttpResponseRedirect, and default tag, maybe something I don't
remember.
--
I like python!
My Blog: http://www.donews.net/limodou
My Django Site: http://www.djangocn.org
NewEdit Maillist: http://groups.google.com/group/NewEdit
Can't you just use "include"?
urlpatterns = patterns('',
('^%s/' % app_prefix, include('app.urls')),
)
Pretty flexible, pretty simple, and already there!
-rob
No, urlconf just one place, we also have view and template need to
deal with. and how to define app_prefix, in urlconf? or in settings?
Need app_prefix be global visiable?
I remember there is also model need to deal with. So there are four
places need to think about:
1. urlconf
2. view
3. template
4. model
Last I checked, none of my views have URLs, other than redirects to
relative paths like '../' or 'thanks/' or redirects to major pages like
'/' and '/member/login/'. As for my templates, certainly my
site-specific templates have URLs for navigation, but all of my
app-specific templates get along just fine with relative paths and
model_object.get_absolute_url.
Maybe if you just focused on clean code you wouldn't have to worry about
baroque complexes of settings?
--
--Max Battcher--
http://www.worldmaker.net/
"I'm gonna win, trust in me / I have come to save this world / and in
the end I'll get the grrrl!" --Machinae Supremacy, Hero (Promo Track)
My solution is not a new idea. You can see:
And there are many people except me consider that: django need a good
urls system:
Jacob Kaplan-Moss
-----------------------------------
As far as I'm concerned, the problem has always been one of syntax
and simplicity. Obviously the model is the wrong place to put a URL
for all the reasons discussed, but you can't beat it for simplicity.
I've tried a few times to come up with a solution that's both
"correct" and just as simple, and each time I've failed. As far as
I'm concerned, if someone can come up with a way to do this that's
stupidly simple then I'm all for a change, but at the same time
get_absolute_url() is a wart I'm willing to live with.
Adrian Holovaty
------------------------------
Yeah, precisely. Elegant solutions are quite welcome!
Adrian
And in my project woodlog, I have many apps just like blog, rss,
comment, tags, profile, etc. And each of them has a app prefix to
distinguish each other, so the top level urls.py is just like:
urlpatterns = patterns('',
(r'^$', 'apps.digest.views.index'),
(r'^blog/$', 'apps.frontpage.views.index'),
(r'^help/$',
'django.views.generic.simple.direct_to_template',{'template':'home/help'}),
('^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}),
('^login/$', 'public.apps.account.views.main.login'),
('^register/$', 'public.apps.account.views.main.register'),
(r'^setting/', include('apps.profile.urls')),
(r'^RPC/?$', 'apps.woodlog.rpc.call'),
(r'^medias/(?P<path>.*)$', 'django.views.static.serve', media_dict),
(r'^admin/', include('django.contrib.admin.urls')),
(r'^test/', include('public.apps.test.urls')),
(r'^comment/', include('public.apps.comment.urls')),
(r'^blog/(?P<user_name>.*?)/', include('apps.woodlog.urls')),
(r'^rss/', include('apps.rss.urls')),
(r'^search/', 'apps.search.views.search'),
(r'^blogers/$', 'apps.frontpage.views.bloglist'),
(r'^tags/$', 'apps.frontpage.views.tags'),
(r'^tags/(?P<name>.*?)/$', 'apps.frontpage.views.taglist'),
(r'^digest/', include('apps.digest.urls')),
)
And I can use rss, tags, profile, comment in blog app, and also I can
use profile, rss in digest app. So apps can reference each other. And
how to use them in url?
For example, in blog app, if I want to use rss, I need:
/rss/something
so if the rss url prefix is changed, so we need change all files which
use '/rss' string. And if the /rss/something is defined
/$rss/something, so even though the rss app urlprefix is changed, we
still don't need to change the files which use '/$rss' string.
Why the app prefix would change, I think there are many reasons, for example:
1. reuse some app, and these apps maybe conflict with existed ones.
2. want to redefine the url, and make them more clean
3. also can used for media prefix
Some static media files need to store in a folder, and configure the
url prefix in someplace, so when we define a url of a css or image, we
can define it as:
<a href="/medias/a.gif">aaaa</a>
So if the template use fixed '/medias' prefix, and if the medias must
be changed, we should do many replacement work. And if we define above
code as:
<a href='/$medias/a.gif'>aaaa</a>
we just need to change the remap rule, and no need to change the
template file at all. And if we copy template or other things just
like view, etc, the modification will be the least, and I think it's
flexible enough.
But Aquarium is not Django, it's another web framework.
You've taken this completely out of context; as I understand it, Jacob
and Adrian were not saying that the *entire* URL system should be
replaced, only that the 'get_absolute_url' method for models doesn't
feel right and they'd like to have something more elegant to take its
place.
--
"May the forces of evil become confused on the way to your house."
-- George Carlin
But isn't this connected? If you don't like ``get_absolute_url``, let's
talk about alternatives. limodou simply did a proposal ... that's a
valid point to discuss. And, hey, you're very restricted with relative
urls, and even these can break when you re-organize the hierarchy of
your urls.
To carry this forward, I see things different than limodou:
* I want to do url configuration in exactly one place
* Any application's urls.py config cannot easily use url config settings
from somewhere else, because it needs regexps.
==> The natural place for the whole url configuration, inclusive
something like get_absolute_url() in urls.py. Not the settings.
The problem is, urls.py knows all about the prefixes where all the model
views are linked in. It even knows how to add fields of the model into
the url if you use %(name)s syntax.
Why not do it like this:
{{{
# within urls.py
(urlpatterns, url_dict) = generate_urlpatterns(
('model-name', 'regexp-prefix', view, optional_kwdict_for_view),
...)
}}}
generate_urlpatterns returns the a tuple (urlpatterns, url_dict)
url_dict is: { model_name : get_absolute_url_fn }
model_name is: a string, containing the name of the model
get_absolute_url is: a function fn(model_instance) --> string
including another urls.py would look like this:
{{{
(urlpatterns, url_dict) = generate_urlpatterns(
...,
('application', 'regexp-prefix', include('fitzefatze.urls')))
}}}
If you want to use this stuff somewhere in a view or model, do:
{{{
from yourapp import urls
from django.jabberwocky import get_absolute_url
# somewhere deep in the code ...
get_absolute_url(urls, obj)
}}}
I see only one two problems in this:
* how to generate the string from the regular expression
* you tie the urls to the field names in the model
But both look feasible to me. Or are there any gotchas? I admit that I'm
not so deep into the url configuration internals (yet).
If there's enough interest, I'm willing to produce a patch for this with
the jabberwocky, of course. If you ain't afraid :-)
Michael
One place for each project? One place for each application? One place
for each model? The problem is that each of these has perfectly valid
use cases for wanting to specify its own URL structure.
> I see only one two problems in this:
> * how to generate the string from the regular expression
> * you tie the urls to the field names in the model
That second one would be a showstopper for me.
One place for each application, but tied in with the include prefixes
from urls. Maybe overwriteable like currently.
>>I see only one two problems in this:
>>* how to generate the string from the regular expression
>>* you tie the urls to the field names in the model
>
>
> That second one would be a showstopper for me.
I feared this might turn out a problem. I haven't so much experience
with different projecs, can you explain a litte about the problems with
this?
Michael
Michael Radziej schrieb:
> The problem is, urls.py knows all about the prefixes where all the model
^^^^^^^ read: point
> If you want to use this stuff somewhere in a view or model, do:
>
> {{{
> from yourapp import urls
> from django.jabberwocky import get_absolute_url
>
> # somewhere deep in the code ...
> get_absolute_url(urls, obj)
> }}}
Or rather, in the model superclass, let's define the method
get_absolute_url(self, urls_module):
return urls_module.url_dict[self._meta.object_name](self)
Michael
I think is not very simple. And I don't see that how to resolve apps
url prefix. Or you just want to resolve get_absolue_url.
You're right. We should go from settings.ROOT_URLCONF downward, anyway,
and not take any url module as parameter, which wouldn't work out in
reality.
I'm not saying this is the solution. But I think this is the way to go.
Anybody else interested in this at all, or am I wasting my time?
Michael
Tying the URL structure to the internals of the application's code,
which is what you seem to be saying your proposal would do, limits a
developer's flexibility to choose the URLs that are most appropriate
to the actual content, and often forces the use of URLs which seem to
have little to do with the content they display.
Have you read through the proposal? I don't tie the URL structure to the
internals of of the application's code. Quite to the opposite.
Michael
Then why did the original email say that it would "tie the urls to the
field names in the model"?
I'm sorry if my reply was a little bit too short.
The bottom line of my proposal is to tie get_absolute_url() to the url
configuration in urls.py. This will need a little twisting of urls.py,
but I hope to do it in a quite and unobtrusive way. It should still be
overwriteable; I'm aware that there are corner cases you cannot solve in
this way.
Don't take the sketch of implementation too important, it's really very
rough and only an outline.
This is not a "I want you to do this" type of proposal, but a mere "Do
you think it's a good idea if I'd do this" :-)
Michael
Let's suppose you have an url config like this (current syntax, urls.py):
urlpatterns = patterns('mailadmin.views',
(r'^(?P<id>[1-9]\d*), 'edit_foobar')),
# ...
)
Then you'd have to match the 'id' group to the id field of whatever
you're going to edit. So, if you later change to rename this field, you
have to change url configuration, which is not nice.
Michael
I think this case is not very well. Because id will be a parameter,
it'll not be an apps url prefix commonly.
Short answer: yes, many people want this problem to be solved.
In fact it was debated ~6 months ago here:
http://code.djangoproject.com/ticket/672 (rather inappropriate place to
have discussions). We discussed different approaches to the problem, use
cases we want to solve, and ... we didn't have a good solution. Look the
ticket up and see, if you can extract anything useful.
Thanks,
Eugene
thanks for the pointer. I suspected it's not been the first
discussion--but it's hard to find. Now, I'll need some time to digest ;-)
Michael
We have urls.py already, which maps urls -> views. Most of the proposals so far
for getting urls back seem to have revolved around getting a url for a model --
I think this is looking at the situation the wrong way. We're not redirecting
people to an object. We're redirecting people to a view of an object.
My proposal for url mapping is that we can specify a specific view we want to
redirect people to, and provide the right arguments to fill that url out.
Eg, given a urlpatterns of
urlpatterns = patterns('',
(r'^(?P<slug>[a-z0-9\-_]+)/subscribe/$',
'taravar.apps.newsletters.views.subscribe'),
)'
We could import a urlresolver module (maybe? haven't thought about this bit
much) and tell it we want to send the user to the
taravar.apps.newsletters.views.subscrie view, with slug=newsletter.slug
Maybe in code it'd be
import urlresolver
url = urlresolver.url('taravar.apps.newsletters.views.subscribe',
slug=newsletter.slug)
Thoughts? Criticisms? I've had this idea bouncing around for a while but have
yet to flesh it out.
--
Lach
Personal: http://illuminosity.net/
That was my point in the ticket #672.
> My proposal for url mapping is that we can specify a specific view we want to
> redirect people to, and provide the right arguments to fill that url out.
Sounds good but the devil is in the details of implementation.
> We could import a urlresolver module (maybe? haven't thought about this bit
> much) and tell it we want to send the user to the
> taravar.apps.newsletters.views.subscrie view, with slug=newsletter.slug
>
> Maybe in code it'd be
>
> import urlresolver
>
> url = urlresolver.url('taravar.apps.newsletters.views.subscribe',
> slug=newsletter.slug)
>
> Thoughts? Criticisms? I've had this idea bouncing around for a while but have
> yet to flesh it out.
Is it going to be imported in a view or in a model? I am more inclined
to include this kind of functionality in a view. In this case we have
two problems, which should be resolved somehow:
1) It looks like the view should know the name of your project (e.g.,
'taravar'), and the name of your app (e.g., 'newsletters'). What if I
use this app in different project? What if I renamed it for some
reasons? Obviously it can be addressed by some introspective variables,
or by configuration parameters, or a request variable can carry this
information derived during url processing.
2) If we are not going to have get_absolute_url(), we have to provide a
default view. It appears to be useful in some special situations, like
in the Admin. How to do it? One way is to follow "convention over
configuration" path requiring a default name (or url) to be available
for that.
If you want to put this functionality in the model, you have even more
problems.
Additionally the solution should be simple, non-taxing in typical cases,
and useful for reusable applications.
Thanks,
Eugene
I described my proposal in :
>
> > We could import a urlresolver module (maybe? haven't thought about this bit
> > much) and tell it we want to send the user to the
> > taravar.apps.newsletters.views.subscrie view, with slug=newsletter.slug
> >
> > Maybe in code it'd be
> >
> > import urlresolver
> >
> > url = urlresolver.url('taravar.apps.newsletters.views.subscribe',
> > slug=newsletter.slug)
> >
> > Thoughts? Criticisms? I've had this idea bouncing around for a while but have
> > yet to flesh it out.
>
> Is it going to be imported in a view or in a model? I am more inclined
> to include this kind of functionality in a view. In this case we have
> two problems, which should be resolved somehow:
>
> 1) It looks like the view should know the name of your project (e.g.,
> 'taravar'), and the name of your app (e.g., 'newsletters'). What if I
> use this app in different project? What if I renamed it for some
> reasons? Obviously it can be addressed by some introspective variables,
> or by configuration parameters, or a request variable can carry this
> information derived during url processing.
I think view indeed needs to know the name of the project or the app,
but the name should be just a name, but not concerned with url. And if
we define a relationship between such names and urls, so the first
step is ok. Next we should resolve, how to define it easily, and hwo
to convert they easily. So in my proposal, I just define a dict to map
name and url, just like:
MAP_RULES = (
('name1', 'url1'),
('name2', 'url2'),
)
This one in not very same like my original proposal. And you can
ealily convert it to a dict, it just like settings.py format. Or
directly define it as a dict, that's ok.
So there are four places we should think about:
1. urls.py
2. view
3. template
4. model
And we also need to decide how to define a mapping rule easily. And I
think we can also use the common way we just do in out codes: string
format, and we also can provide some helper function to do that. How
to define a mapping rule in string? I think out some formats:
'$name/page' #using '$' as the prefix, but these one may be conflict
with regx '$'
'<name>/page'
'{name}/page'
'{!name!}/page'
and many formats we can think out.
Also we can provide some helper function:
get_mapping_rule('name') + '/page'
So we have many appoaches in different places. And I think using
string format is the easiest way:
in urls.py, we can :
(r'^{!blog!}/(?P<user_name>.*?)/', include('apps.woodlog.urls')),
in views, we can:
HttpResponseRedirect('/{!blog!}/username/feb')
in template, we can:
<a href="{!blog!}/page">{{ title }}</a>
and in model, we can do it just like in views:
def get_relative_url(self):
return str(object.id)
def get_absolute_url(self):
return '{!blog!}/%s' % self_get_relative_url()
>
> 2) If we are not going to have get_absolute_url(), we have to provide a
> default view. It appears to be useful in some special situations, like
> in the Admin. How to do it? One way is to follow "convention over
> configuration" path requiring a default name (or url) to be available
> for that.
>
> If you want to put this functionality in the model, you have even more
> problems.
>
> Additionally the solution should be simple, non-taxing in typical cases,
> and useful for reusable applications.
>
> Thanks,
>
> Eugene
>
--