Overthinking urls.py?

28 views
Skip to first unread message

Doug Van Horn

unread,
Mar 27, 2006, 4:23:34 PM3/27/06
to Django users
Disclaimer: I'm new to Python and Django, but I've been coding Java
since '98.

In thinking about the url definitions in urls.py, it occurs to me that
a major rewrite of the url patterns could prove to be a pain. For
example, I have an app where the urls are deployed under /foo/, and I
have a URL defined as '^bar/\d+/$'.

When drawing a link to that view in HTML from another app I would 'hard
code' that URL as, say, 'href="/foo/bar/99"'.

Now say I come along and change my foo application, such that the URL
is newly defined as, '^quux/\d+/bar/$'. Everywhere I've hard coded
that link will now be affected, requiring code changes and testing.
I've tightly coupled my app urls.

In response to this problem, my over-engineering brain tells me to
create 'URL' objects, containing the regex defining the URL as well a
way to 'construct' a 'real' URL.

In my example, the calling application would now have something like
bar_url = BarURL(bar=99). I would then use this object to render a
'real' url as such, 'href="{{ bar_url.render_link }}"'. The calling
application would only need to know that a BarURL needs a bar parameter
to construct a valid URL. The BarURL class would be responsible for
defining the regex, constructing a valid URL, and somehow picking up
the deployed application prefix (/foo/ in our case).

Finally, the urls.py module in my foo application would do something
like 'BarURL.REGEX' where one would normally define the regexes for an
application, e.g., (BarURL.REGEX, 'app.foo.views.bar'),.


Anyway, am I overthinking this whole thing? I'm not asking for a
patch, but rather advice on whether this kind of thinking/approach
makes sense in the Django framework? Is it 'pythonic', as they say?
It seems somewhat OO to me, and I like encapsulating the behavior
inside a class. I guess I'm just looking for some seasoned expert
opinions. Well, any opinions really.


Thanks!
doug.

Julio Nobrega

unread,
Mar 27, 2006, 4:51:06 PM3/27/06
to django...@googlegroups.com
What about mod_rewrite? And urls.py (afaik) can serve two different
paths to the same view.

On 3/27/06, Doug Van Horn <dougv...@gmail.com> wrote:
>
> When drawing a link to that view in HTML from another app I would 'hard
> code' that URL as, say, 'href="/foo/bar/99"'.


--
Julio Nobrega - http://www.inerciasensorial.com.br

Max Battcher

unread,
Mar 27, 2006, 5:03:40 PM3/27/06
to django...@googlegroups.com
> Anyway, am I overthinking this whole thing?

Yes. The major pattern in Django is that your model objects should have a:

def get_absolute_url(self):
return "/bar/%s/" % (self.id)

Then when you change the URL scheme you can either update your model
objects, or in cases where there are multiple uses of your model
objects (ie, two projects sharing an application), Django also
provides, for your settings.py file, the ABSOLUTE_URL_OVERRIDES
setting, which you can look up in the appropriate documentation.

--
--Max Battcher--
http://www.worldmaker.net/
All progress is based upon a universal innate desire on the part of
every organism to live beyond its income. --Samuel Butler

Eric Walstad

unread,
Mar 27, 2006, 5:13:52 PM3/27/06
to django...@googlegroups.com
On Monday 27 March 2006 13:23, Doug Van Horn wrote:
> When drawing a link to that view in HTML from another app I would
> 'hard code' that URL as, say, 'href="/foo/bar/99"'.
>
> Now say I come along and change my foo application, such that the
> URL is newly defined as, '^quux/\d+/bar/$'.  Everywhere I've hard
> coded that link will now be affected, requiring code changes and
> testing. I've tightly coupled my app urls.
>
> In response to this problem, my over-engineering brain tells me to
> create 'URL' objects, containing the regex defining the URL as well
> a way to 'construct' a 'real' URL.

we've now spent more time over-engineering than it would take to
sed "s/href=\"\/foo/href=\"\/quux/g" urls.py

I wonder what the half life is of 9 years of Java contamination?

wink-wink-nod-nod-ly yours,

Eric.

Adrian Holovaty

unread,
Mar 27, 2006, 5:21:09 PM3/27/06
to django...@googlegroups.com
On 3/27/06, Doug Van Horn <dougv...@gmail.com> wrote:
> In thinking about the url definitions in urls.py, it occurs to me that
> a major rewrite of the url patterns could prove to be a pain. For
> example, I have an app where the urls are deployed under /foo/, and I
> have a URL defined as '^bar/\d+/$'.
>
> When drawing a link to that view in HTML from another app I would 'hard
> code' that URL as, say, 'href="/foo/bar/99"'.

Hey Doug,

The convention is to put the URL-creation logic in your models, in a
get_absolute_url() method. Here's a quick example:

class Person(meta.Model):
gender = meta.CharField(maxlength=1) # 'm' or 'f'
full_name = meta.CharField(maxlength=50)

def get_absolute_url(self):
return '/people/%s/%s/' % (self.gender,
self.full_name.lower().replace(' ', ''))

You're right to imply that this goes against the DRY principle,
because you have to define URLs in two places -- the URLconfs and the
models. In practice, this isn't that big of a deal (in my humble
opinion), but we've given some thought to putting the
get_absolute_url() logic in URLconfs instead, so at least the logic is
in a single file.

Adrian

--
Adrian Holovaty
holovaty.com | djangoproject.com

ToddG

unread,
Mar 27, 2006, 7:12:51 PM3/27/06
to Django users
Perhaps for a rainy day (very future release):
http://routes.groovie.org/

limodou

unread,
Mar 27, 2006, 8:11:56 PM3/27/06
to django...@googlegroups.com
I think your thought is very well. And I also faced the same situation
as you. And I also think different application need has different url
prefix, and all its functions should be related to the prefix. So a
real application will be:

prefix + function_name + parameters

And these things should be implemented both in urls.py and views or
template code. But now there is not a official method to do that. So I
defined myself pattern to do that:

first, I defined a mapping between application and prefix in
settings.py, just like:

APP_ROOT = {'blog':'blog', 'setting':'setting', 'tags':'tags',
'medias':'medias'}

second, I wrote some function and custom tag in order to get the app's prefix

So in views and template code I can get a certain app's prefix through
by a function get_app_root('blog') (written by myself) or by a custom
tag {% get_app_root "blog" %}. So I only need to deal with
function_name + parameters is ok, just like:

url = get_app_root('blog') + / + 'function_name/parameters/'

in template

<a href="{% get_app_root "blog" %} / functioin_name/parameters">xxx</a>

--
I like python!
My Blog: http://www.donews.net/limodou
NewEdit Maillist: http://groups.google.com/group/NewEdit

Glenn Tenney

unread,
Mar 27, 2006, 8:41:30 PM3/27/06
to django...@googlegroups.com
On Mon, Mar 27, 2006 at 04:21:09PM -0600, Adrian Holovaty wrote:
> The convention is to put the URL-creation logic in your models, in a
> get_absolute_url() method. Here's a quick example:
> ...

> You're right to imply that this goes against the DRY principle,
> because you have to define URLs in two places -- the URLconfs and the
> models. In practice, this isn't that big of a deal (in my humble
> opinion), but we've given some thought to putting the
> get_absolute_url() logic in URLconfs instead, so at least the logic is
> in a single file.

I believe that anything to do with a URL certainly does NOT belong in
the model. Models are, in part, an abstraction of the data... the
scheme... etc. Models should have nothing to do with the URL for an
object! And that has nothing to do with whether the data appears in
one or many places... the Model just isn't the right place for this
data to be defined.

While I know that the URLconfs is Python code, it doesn't seem that
that's the right place either... from an abstraction point of view.
The place that seems "right" is in the view itself... or perhaps
actually at the template level. If in the view, it would need the
URLconfs passing to the view the "base" of the URL that matched this
view (or a dict or something, not necessarily the actual RE match!).

Even doing it in the view will be "tough" since:

a) different objects displayed in a view might have very
different URL paths -- paths "outside" the view.

b) normally it's the template that's actually displaying
or making use of the URL of an object. A template T1
may want the url of object X to be different than that
same object when displayed in template T2.

--
Glenn

Julio Nobrega

unread,
Mar 27, 2006, 9:57:11 PM3/27/06
to django...@googlegroups.com
I like the URLs at the model. Think in terms of URI (Uniform
Resource Identifiers). The .get_absolute_url() tells how the model can
be found. It's part of the "rules that give access" to data.

On 3/27/06, Glenn Tenney <gt-d...@think.org> wrote:
> Models are, in part, an abstraction of the data... the
> scheme... etc. Models should have nothing to do with the URL for an
> object!

--

Ivan Sagalaev

unread,
Mar 27, 2006, 11:55:35 PM3/27/06
to django...@googlegroups.com
Adrian Holovaty wrote:

>The convention is to put the URL-creation logic in your models, in a
>get_absolute_url() method.
>

Thank you Adrian and others for this info! All this time I was honestly
thinking that hard-coded urls in templates are some kind of evil that
need to be dealt with in future. :-)

Doug Van Horn

unread,
Mar 28, 2006, 8:04:09 AM3/28/06
to Django users
A sed won't work in all situations as it relies on the fact that you
constuct the URL in a particular way. What if the URL is constructed
dynamically in a template? Or in code?

Not to mention the fact that it breaks application encapsulation. If I
have ten integrated apps deployed a syntax change to one application
can ripple through the other 9. Java contamination or no, that's not
good code.

Not to belabor the point, but I think the concern has merit.

doug.

Doug Van Horn

unread,
Mar 28, 2006, 8:17:52 AM3/28/06
to Django users
> ...but we've given some thought to putting the

> get_absolute_url() logic in URLconfs instead, so at least the
> logic is in a single file.

I'm not as concerned with where it's encapsulated, just that it is.

I didn't know about the get_absolute_url() method and the
ABSOLUTE_URL_OVERRIDES mentioned earlier in the thread. I'll be sure
to check them out.

I think the real goal I was aspiring to was protecting one application
from another, i.e., having a sane way to cross link applications and
protect others from my changes. The only issue I have with the model
holding the URLs would be that an application's URLs are not always
oriented around one particular model. So you're not really covered in,
say, a wizard workflow.

Anyway, back to slinging Java for another 8 hours. w00t!

doug.

pbx

unread,
Mar 28, 2006, 9:55:23 AM3/28/06
to Django users
I think rolling functionality similar to ABSOLUTE_URL_OVERRIDES into
URLconfs is the way to go. As others have pointed out,
get_absolute_url() doesn't cover enough ground and creates unnecessary
coupling.

Simon expresses it well here:

http://groups.google.com/group/django-developers/msg/98ee1a543c40e123

Jacob Kaplan-Moss

unread,
Mar 28, 2006, 1:19:39 PM3/28/06
to django...@googlegroups.com

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.

Jacob

Glenn Tenney

unread,
Mar 28, 2006, 1:37:08 PM3/28/06
to django...@googlegroups.com
On Tue, Mar 28, 2006 at 12:19:39PM -0600, Jacob Kaplan-Moss wrote:
> "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.


Just thinking aloud...

In the model you want to know "what is this object's identifier that
we would use in a url". That might be just an object ID, a slug,
or maybe yyyy/mm/dd/id or who knows what. This would be formated
such that it could be used as-is as PART of a URL. Let's call this method
"get_id_for_url()" (or whatever you end up calling it) That seems to be
the appropriate type of data to come from a Model.. i.e. not the entire
absolute URL, but just a portion of the URL that would be used to
identify this Model's object.

Then, in the particular view (not clear, it might be and/or in the
template) you would want to combine some base URL string with the
previous get_id_for_url string to make it into a real url. To do that
might need just a variable "base_url" (or it could be yet another view
specific method) that changes by the view.

So in a template you'd have to do
{{ base_url }}{{ this-object.get_id_for_url }}

In your urls.py and/or view you'd setup a dict to pass the appropriate
value to the template e.g.
info_dict = {
'app_label': 'myapp',
'module_name': 'mymods',
'base_url': 'mymods',
}

That would allow me to use the generic views if I sent the 'base_url' correctly,
or you could even have it default to the 'module_name'. Or I could code
it into my view's code however I wish.

?????

--
Glenn

Max Battcher

unread,
Mar 28, 2006, 1:40:40 PM3/28/06
to django...@googlegroups.com
On 3/28/06, pbx <paul....@gmail.com> wrote:
> I think rolling functionality similar to ABSOLUTE_URL_OVERRIDES into
> URLconfs is the way to go. As others have pointed out,
> get_absolute_url() doesn't cover enough ground and creates unnecessary
> coupling.

You realize that because ASOLUTE_URL_OVERRIDES takes arbitrary
functions you could do that today with no framework changes? (Might
be something worthy of an addition to the body of shortcuts, though,
if someone comes up with a decent version.)

Off the top of my head (don't blame me if it has bugs):

def urlfromconf(object, path):
urlconf = __import__(path)
return urlconf.absolute_url(object)

ABSOLUTE_URL_OVERRIDES = {
'myapp.somemodel': lamda o: urlfromconf(o, 'myapp.urls.somemodelrelated'),
}

Then in myapps.urls.somemodelrelated:

def absolute_url(object):
return "/path/to/object/%s/" % (object.id)

Arthur

unread,
Mar 28, 2006, 1:44:48 PM3/28/06
to django...@googlegroups.com
> > "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.
>
> In the model you want to know "what is this object's identifier that
> we would use in a url". That might be just an object ID, a slug,
> or maybe yyyy/mm/dd/id or who knows what. This would be formated
> such that it could be used as-is as PART of a URL. Let's call this method
> "get_id_for_url()" (or whatever you end up calling it) That seems to be
> the appropriate type of data to come from a Model.. i.e. not the entire
> absolute URL, but just a portion of the URL that would be used to
> identify this Model's object.
>
> Then, in the particular view (not clear, it might be and/or in the
> template) you would want to combine some base URL string with the
> previous get_id_for_url string to make it into a real url. To do that
> might need just a variable "base_url" (or it could be yet another view
> specific method) that changes by the view.
>
> So in a template you'd have to do
> {{ base_url }}{{ this-object.get_id_for_url }}
>
> In your urls.py and/or view you'd setup a dict to pass the appropriate
> value to the template e.g.
> info_dict = {
> 'app_label': 'myapp',
> 'module_name': 'mymods',
> 'base_url': 'mymods',
> }
>
> That would allow me to use the generic views if I sent the 'base_url' correctly,
> or you could even have it default to the 'module_name'. Or I could code
> it into my view's code however I wish.

That's similar to what I do. The get_absolute_url() concatenates a
<SOME_APP>_BASE_URL from settings.py or from the top of models.py with
what you call get_id_for_url. This isn't completely clean but easy to
change if you remember where to look for the constant.

Arthur

Glenn Tenney

unread,
Mar 28, 2006, 2:17:00 PM3/28/06
to django...@googlegroups.com
On Tue, Mar 28, 2006 at 08:44:48PM +0200, Arthur wrote:
> That's similar to what I do. The get_absolute_url() concatenates a
> <SOME_APP>_BASE_URL from settings.py or from the top of models.py with
> what you call get_id_for_url. This isn't completely clean but easy to
> change if you remember where to look for the constant.

Because the "url" for an object might be different depending on
how you wanted to "see" that object (i.e. depending on the current
view), in your way you'd have to make "get_absolute_url" not actually
be the ABSOULTE URL... and THAT is the point in what I was suggesting.

That the part of the URL "in front" of the object's unique part is
not a constant for the entire settings.py, but rather is variable
based on the view / tempalte.

--
Glenn

limodou

unread,
Mar 28, 2006, 7:59:18 PM3/28/06
to django...@googlegroups.com

I was do the similar thing. I put a dict in settings.py just like:

APP_ROOT = {'blog':'blog', 'setting':'setting'}

HOST_URL = 'http://mydomain.com'

And I provide some api for get the combined url like:

url = join_app_path('blog', obj.url())

In here, obj.url() just a related path according to the application
url. And join_app_path will auto pick up the HOST_URL, so the result
will be:

'http://mydomain.com/blog/' + obj.url()

the join_app_path will automaticly deal with '/'.

APP_ROOT represents different application url prefix but not including domain.

daniel...@gmail.com

unread,
Mar 29, 2006, 3:43:27 AM3/29/06
to Django users
Adrian Holovaty wrote:
> The convention is to put the URL-creation logic in your models, in a
> get_absolute_url() method. Here's a quick example:
>
> class Person(meta.Model):
> gender = meta.CharField(maxlength=1) # 'm' or 'f'
> full_name = meta.CharField(maxlength=50)
>
> def get_absolute_url(self):
> return '/people/%s/%s/' % (self.gender,
> self.full_name.lower().replace(' ', ''))

I find this *really* surprising. All discussions and examples I've seen
so far are quite strict about the fact that models should be separate
from presentation logic. See the various discussions about "how can my
model get access to request.user?" here in this group. These arguments
made (make) perfect sense to me.

And now you're encoding URLs (which are, in my mind, definitely
presentation-related) in the models? To me, this seems strange and
unnatural. Why should a "Book" model care wether it has a view that
lives under "/library" or under "/amazon/shoppingcart" or under
"/thingtostopthetablefromwobbling" ? It's a book. It has properties. It
knows how to tell me its title.

But it shouldn't care wether it's being read or being used to prop up
furniture.

Or am I misunderstanding something here?

Daniel

limodou

unread,
Mar 29, 2006, 4:06:57 AM3/29/06
to django...@googlegroups.com

Because I think model in Django is not a simple data wrapper layer,
but also a representation layer in many situations. If you don't want
model do much, so you need do such things(create url) in other places.
And if there is not a good way to create url, I think create url by
model itself is a handy way.

And I think there should be a good way to create url, which will
consider different applications, functions, and object_ids. Even
user_id in it.

James Bennett

unread,
Mar 29, 2006, 4:24:02 AM3/29/06
to django...@googlegroups.com
> And now you're encoding URLs (which are, in my mind, definitely
> presentation-related) in the models?

It's not something new; it's been this way since the first public
release of Django. Adrian and others have said elsewhere that it's not
nice and they'd love to see a better way to handle this, but no-one's
yet come up with one that works.

--
"May the forces of evil become confused on the way to your house."
-- George Carlin

Kevin

unread,
Mar 29, 2006, 2:16:19 PM3/29/06
to Django users
I think the problem is that urlconf provides a url => view mapping.
Really though, for creating the links, we need the reverse mapping. We
usually know the view we want to display, but don't know it's URL.

For example, you have a bulletin board app:

urls.py:
urlpatterns = patterns(''
'^comments/(\d+)/', 'sample.bboard.view_comment')
.....

def view_comment(id):
comment = Comment.objects.get(id)
responses = comment.responses.all()
render_to_response('template', {'comment': comment, 'responses':
responses})


Currently, you could define the template like this:
template.html:
.....
{% for response in responses %}
<a href="{{ response.get_absolute_url }}">{{ response.title }}</a>
{% endfor %}

But, really, all you want is a tag like this:
{% for response in responses %}
<a href="{% view_function_url 'sample.bboard.view_comment' response.id
%}">{{ response.title}}</a>

Adrian Holovaty

unread,
Mar 29, 2006, 10:38:12 AM3/29/06
to django...@googlegroups.com
On 3/29/06, James Bennett <ubern...@gmail.com> wrote:
> On 3/29/06, daniel...@gmail.com <daniel...@gmail.com> wrote:
> > And now you're encoding URLs (which are, in my mind, definitely
> > presentation-related) in the models?
>
> It's not something new; it's been this way since the first public
> release of Django. Adrian and others have said elsewhere that it's not
> nice and they'd love to see a better way to handle this, but no-one's
> yet come up with one that works.

Yeah, precisely. Elegant solutions are quite welcome!

Todd O'Bryan

unread,
Mar 29, 2006, 5:39:53 PM3/29/06
to django...@googlegroups.com
Is it possible to do it all in urls.py? I don't know much about
Python, yet, but could you have two way look-up. urls.py has the URL-
>View handled. Could you stick in a dictionary based on classes (and
PKs, maybe) that would return the appropriate URL?

Todd

Doug Van Horn

unread,
Mar 30, 2006, 11:58:13 AM3/30/06
to Django users
I'm going to type out loud for a little bit. I'm hoping to better
define the problem so we can think about solutions more clearly (or go
find ones as solved by other frameworks).

Django has the concept of an application, a reusable chunk of
functionality which can be reused in many different projects. A
project is a collection of applications.

A project is responsible for defining which apps are available
(INSTALLED_APPS), and what URL the app can be accessed under, e.g.,
(r'^admin/', include('django.contrib.admin.urls.admin')).

== Problem ==
If application Foo wishes to link to application Admin, it must know
how the Project has 'mapped' the Admin application (e.g., starts with
/admin/).

This leads in to the original topic of the thread, which centers around
encasulating URLs; gathering their RE and their 'parameters' into one
class for reuse.

== Problem ==
If application Foo wishes to link to application Admin, it must know
how the URL is constructed.


So what does the solution look like?

== 1 ==
Application Foo should be able to use a Class, function, whatever,
supplied by the Admin application, to obtain a URL it can draw in an
HTML page.

== 2 ==
The Admin application should know something about how it has been
deployed by the project to that it can correctly construct a URL to
itself.


== v0.01 Solution ==
INSTALLED_APPS = (
('django.contrib.admin', 'admin',),
('cpt.app.foo', 'foo',),
)

When the framework/project installs an application using this
configuration, it could add a well known variable to the
django.contrib.admin package called 'DEPLOYMENT_PREFIX'.

I don't have a proposal on how to get that variable into the urls.py
module under the project. I haven't thought it through and would
rather skip it for now.

As far as encasulating URLs inside an application, the convention might
be to have a urls.py module which could hold Classes defining URLs. A
URL class might look like this:

class StartWorkflowURL:
"""Defines a bogus URL for testing.
"""

_RE = r'^workflows/foo/(?P<init_param>\d+)/'
_init_param = 0

def __init__(self, init_param=0):
"""URL to a workflow.
"""
self._init_param = init_param

def RE(self):
return self._regex

def url(self):
return '%s/workflows/foo/%d/' % (DEPLOYMENT_PREFIX, self._bar)


The Class RE method allows the RE to be included in urlpatterns:

urlpatterns = patterns('',
(StartWorkflowURL().RE(), 'start_workflow'),
)


I know that this definition could be improved upon (it may not even be
valid Python). There's probably a more 'pythonic' way (I'm a Java guy
who thinks in classes still). But the idea is that if you want to link
to the Admin application, you ask the Admin application to tell you
how.

All right. That's enough for now. Don't know if anyone is interested
in dissecting this, but I thought I'd get it out there as an idea. Not
a proposal, suggestion, or anything else. Just an idea.

ToddG

unread,
Mar 30, 2006, 2:16:14 PM3/30/06
to Django users
I'm not sure if this was earlier missed or ignored by people [nobody
explictly ruled it out], I can't help but think Django's URL handling
will either drift towards re-implementing Routes:
http://routes.groovie.org/ or staying as it is. (note the lastest
version has a nice feature where you can pass in a function to do
pre-processing or whatever you want to args and such before creating a
Route or matching it).

I'll end my broken record impression now, won't mention it again...

Max Battcher

unread,
Mar 30, 2006, 3:07:01 PM3/30/06
to django...@googlegroups.com
On 3/30/06, ToddG <tdg...@gmail.com> wrote:
>
> I'm not sure if this was earlier missed or ignored by people [nobody
> explictly ruled it out], I can't help but think Django's URL handling
> will either drift towards re-implementing Routes:
> http://routes.groovie.org/ or staying as it is. (note the lastest
> version has a nice feature where you can pass in a function to do
> pre-processing or whatever you want to args and such before creating a
> Route or matching it).

I hate to say it, but Routes and most of the other schemes presented
_do_ feel over-engineered. The current URL patterns system is fast
and clean. The get_absolute_url() pattern is simple one, and yes it
might break the "perfect Model seperation", but Django makes no qualms
that it absolutely has to follow MFC or PCMEF or whatever else, but
instead keeps in mind a good idea of what is "pragmatic".

I would only suggest that renaming to perhaps get_canon_url() might be
somewhat less confusing, in that it refers to a canonical URL rather
than the preferred URL or every URL. (For example, my most common
problem is the objects that have many different URLs in the same
project based on semantic differences (ie, same object to admin,
different object to user). In some cases get_absolute_url() points to
the canonical URL that fits 85% of the cases and that view will do
semantic redirects if necessary.)

The ABSOLUTE_URL_OVERRIDES tool is a handy convenience to fix this
seperation problem, and with it you can do all sorts of crazy things
(thanks to the pythonic ability to pass around functions) like
implement your own project-specific mini-routes or whatever (see my
previous post on the subject).

Doug Van Horn

unread,
Mar 30, 2006, 5:51:00 PM3/30/06
to Django users
> I hate to say it, but Routes and most of the other schemes presented
> _do_ feel over-engineered. The current URL patterns system is fast
> and clean.

I actually agree 100%. And my earlier post indeed smacks of
overengineering. And in my current smallish project I don't intend to
do any of that kind of encapsulation.

With that said, I do think that the issue has legs if you were to pull
in 3 or 4 or 5 projects from different sources to create some kind of
new all-encompassing proejct. E.g., Admin, ShoppingCart, Inventory,
and PayPayIntegration. (Assuming those to be 3rd party apps).

It certainly doesn't need to be solved for me to use Django, though.

See? As I promised, I've overthought this whole thing. I _must_ learn
to think more agile. :-(

Glenn Tenney

unread,
Mar 30, 2006, 6:21:40 PM3/30/06
to django...@googlegroups.com
On Thu, Mar 30, 2006 at 03:07:01PM -0500, Max Battcher wrote:
> I hate to say it, but Routes and most of the other schemes presented
> _do_ feel over-engineered. The current URL patterns system is fast
> and clean. The get_absolute_url() pattern is simple one, and yes it
> might break the "perfect Model seperation", but Django makes no qualms
> that it absolutely has to follow MFC or PCMEF or whatever else, but
> instead keeps in mind a good idea of what is "pragmatic".

Earlier this week I noted that I believe get_absolute_url just does not
belong in the Models... period. I suggested an alternative that I think
would be easy to use, easy to implement, and would "fit".

I didn't however, try to suggest the exact Django way to describe it
since I was specifically trying to NOT get bogged down into that
naming / implementation idea, rather to let the developers mull on
it as one idea to consider.

But, it didn't seem to get any comments pro or con, so let me try again:

I believe that the Model should have a common method used
to get a PART of a URL, the part that locates this object. That part
of the URL might be "place/<objectid>" or "poll/<slug>". But that
is not an absolute url. It would then be up to the view (in a generic
view, that should be handled by a dict entry) to pre-pend something in
front of what the model provide to make it a URL.

perhaps:

In Models: get_url()
returns a string that can be used by the view to make up a URL that
uniquely identifies this object.

In urlsconf:
add to "infodict" -- 'url_view': 'polls'

In the view:
you form a url from: URL_BASE + 'url_view' + get_url()
( URL_BASE might not even be needed )


--
Glenn

Max Battcher

unread,
Mar 30, 2006, 8:02:16 PM3/30/06
to django...@googlegroups.com
On 3/30/06, Glenn Tenney <gt-d...@think.org> wrote:
> But, it didn't seem to get any comments pro or con, so let me try again:
>
> I believe that the Model should have a common method used
> to get a PART of a URL, the part that locates this object. That part
> of the URL might be "place/<objectid>" or "poll/<slug>". But that
> is not an absolute url. It would then be up to the view (in a generic
> view, that should be handled by a dict entry) to pre-pend something in
> front of what the model provide to make it a URL.
>
> perhaps:
>
> In Models: get_url()
> returns a string that can be used by the view to make up a URL that
> uniquely identifies this object.
>
> In urlsconf:
> add to "infodict" -- 'url_view': 'polls'
>
> In the view:
> you form a url from: URL_BASE + 'url_view' + get_url()
> ( URL_BASE might not even be needed )

Since I'm feeling vocal: I saw that and I would suggest that I'm -0
on the idea. It is a decent idea, but it isn't so much a framework
need than it is an application/project pattern need. Sure, people are
decrying that there is no "one way" pattern right now, but I think
until one emerges that we can all agree on, there isn't enough pain in
the current process of brokering between applications to warrant the
effort of establishing that standard.

With that said, you are completely free to use the above pattern, or
something similar to it, in _the existing framework_. The current
thing about the current framework functionality being that it is a
simple minimum and it is reasonably powerful. Here's what you could
do:

Create your get_url() functions as you specified. Then you have a
simple enough get_absolute_url():

def get_absolute_url(self):
return DEFAULT_URL_BASE + self.get_url()

That satisfies both you (you just care about the get_url()) and the
Framework (which, really, the only major Framework part that uses
get_absolute_url() is contrib.shortcuts and contrib.admin, and maybe
by now several template designers are used to it).

If you want a dynamic URL base you are even free to create a
get_url_base_from_view() function and call it from
ABSOLUTE_URL_OVERRIDES, like so:

ABSOLUTE_URL_OVERRIDES = {
'myapp.mymodel': lambda o: magic_get_url_base_from_view() + o.get_url(),
}

Again, zero changes to current functionality and you have your custom
functionality that your end users (aka, other developers) may or may
not thank you for when they set out to customize your application, and
it shouldn't interfere with my (or the next developers) own preferred
way of dealing with things (in some ways I'd heavily argue that the
URL scheme is highly dependent on the type of application in question,
anyway, and we aren't going to agree on a standard pattern).

The only feature I could see a call for in this particular case,
because you are going to have a strong, repetitive pattern here in
your ABSOLUTE_URL_OVERRIDES, and that isn't very DRY, is that maybe
you could use some sort of pattern matching in ABSOLUTE_URL_OVERRIDES
like being able to use 'myapp.*' or '[myapp1, myapp2].*'.

Reply all
Reply to author
Forward
0 new messages