Reverse URL lookup implementation

188 views
Skip to first unread message

Adrian Holovaty

unread,
Apr 6, 2006, 4:24:14 PM4/6/06
to django-d...@googlegroups.com
On the plane from London to Chicago yesterday, I implemented something
that's been discussed on this list lately -- "reverse" URL creation.

I've attached a new urlresolvers.py to this e-mail. It's intended to
replace the one in django/core, and it works with magic-removal only.
(To use it with trunk, just replace the import line at the top to
import Http404 from django.core.exceptions instead of django.http.)
I've also attached unit tests.

Given a view name (e.g. 'myproject.polls.views.poll_detail', as a
string) and any number of positional or keyword arguments, this code
generates the URL according to the first URL pattern in your URLconf
that matches.

The method is reverse() on both the RegexURLPattern and
RegexURLResolver classes.

Here's an example of how it works. Given this root URLconf:

urlpatterns = patterns('',
(r'^foo/$', 'path.to.foo_view'),
(r'^dates/(\d{4})/(\w{3})/$', 'path.to.month_view'),
(r'^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'path.to.person_view'),
)

Here's how to use it:

>>> from django.conf import settings
>>> from django.core import urlresolvers
>>> resolver = urlresolvers.RegexURLResolver(r'^/', settings.ROOT_URLCONF)
>>> resolver.reverse('path.to.foo_view')
'foo/'
>>> resolver.reverse('path.to.month_view', '2005', 'apr')
'dates/2005/apr/'
>>> resolver.reverse('path.to.person_view', state='il', name='adrian')
'people/il/adrian/'
>>> resolver.reverse('path.to.person_view', 'il', 'adrian')
'people/il/adrian/'
# In the following, 'invalidstate' fails the regex test (it isn't two
characters long).
>>> resolver.reverse('path.to.person_view', 'invalidstate', 'adrian')
Traceback (most recent call last):
...
NoReverseMatch

Ideally there'd be a template-tag interface to this. Something like:

{% link 'path.to.month_view' 2005 'apr' %}
{% link 'path.to.person_view' state='il' name='adrian' %}

It's implemented by analyzing the regular expression, which was quite
fun. This means it'll probably break for wacky regexes, but I think a
95% solution is fine.

Thoughts?

Adrian

--
Adrian Holovaty
holovaty.com | djangoproject.com

urlresolvers.py
reverse_unit_tests.py

Ivan Sagalaev

unread,
Apr 6, 2006, 4:38:43 PM4/6/06
to django-d...@googlegroups.com
Adrian Holovaty wrote:

>Ideally there'd be a template-tag interface to this. Something like:
>
> {% link 'path.to.month_view' 2005 'apr' %}
> {% link 'path.to.person_view' state='il' name='adrian' %}
>
>

It's unbelievable :-). I was thinking about it just 15 minutes ago but
only with 'url' instead of 'link' :-). And without that much details...

Jacob Kaplan-Moss

unread,
Apr 6, 2006, 4:40:40 PM4/6/06
to django-d...@googlegroups.com
On Apr 6, 2006, at 3:24 PM, Adrian Holovaty wrote:
> On the plane from London to Chicago yesterday, I implemented something
> that's been discussed on this list lately -- "reverse" URL creation.

Wow.

This is frickin' amazing, Adrian; it's exactly what I kept trying to
come up with and couldn't think all the way through.

/me has another "I wish I'd thought of that" moment... :)

Jacob

Jacob Kaplan-Moss

unread,
Apr 6, 2006, 4:47:16 PM4/6/06
to django-d...@googlegroups.com
I just had another thought on this:

On Apr 6, 2006, at 3:24 PM, Adrian Holovaty wrote:

> Ideally there'd be a template-tag interface to this. Something like:
>
> {% link 'path.to.month_view' 2005 'apr' %}
> {% link 'path.to.person_view' state='il' name='adrian' %}

One thing we could do -- to make this even easier -- would be to grab
data from an object passed into the {% link %} tag. So in your
example urlconf::

(r'^people/(?P<state>\w\w)/(?P<name>\w+)/$', 'path.to.person_view'),

If a Person object had ``state`` and ``name`` attributes, you could do::

{% link path.to.person_view person %}

(where ``some_person`` is an object in the context) as a shortcut to::

{% link path.to.person_view state=person.state name=person.name %}

That way if you set up your URLconfs in a logical manner -- I'd bet
90% of my urlconfs already work this way -- the shortcut version
would Just Work™.

Jacob

Max Battcher

unread,
Apr 6, 2006, 5:21:39 PM4/6/06
to django-d...@googlegroups.com
On 4/6/06, Jacob Kaplan-Moss <ja...@jacobian.org> wrote:
> That way if you set up your URLconfs in a logical manner -- I'd bet
> 90% of my urlconfs already work this way -- the shortcut version
> would Just Work™.

Unfortunately the Generic Views don't fit this too well...
'object_id' is not 'id'.

--
--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

limodou

unread,
Apr 6, 2006, 8:55:36 PM4/6/06
to django-d...@googlegroups.com
Great! But whether the syntax can be more easier when we used it in
views or other source code? I think the tag used in template is simple
enough. Maybe be there should be an easy helper function like `link`
to do that. Just like:

>>> from django.core.urlresolvers import link
>>> link('path.to.month_view', '2005', 'apr')
'dates/2005/apr/'

I think it's not difficult.

+1

--
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

Adrian Holovaty

unread,
Apr 6, 2006, 9:48:31 PM4/6/06
to django-d...@googlegroups.com
On 4/6/06, limodou <lim...@gmail.com> wrote:
> Great! But whether the syntax can be more easier when we used it in
> views or other source code? I think the tag used in template is simple
> enough. Maybe be there should be an easy helper function like `link`
> to do that. Just like:
>
> >>> from django.core.urlresolvers import link
> >>> link('path.to.month_view', '2005', 'apr')
> 'dates/2005/apr/'

Yes, we'd expose a simpler API to this -- the example I gave in my
e-mail was low-level.

Eugene Lazutkin

unread,
Apr 6, 2006, 10:49:37 PM4/6/06
to django-d...@googlegroups.com
Finally! :-)

Adrian Holovaty wrote:
> On the plane from London to Chicago yesterday, I implemented something
> that's been discussed on this list lately -- "reverse" URL creation.

On conceptual level it looks similar to what I started to implement for
my site with a small insignificant difference --- your code actually
works and mine doesn't. :D

> Ideally there'd be a template-tag interface to this. Something like:
>
> {% link 'path.to.month_view' 2005 'apr' %}
> {% link 'path.to.person_view' state='il' name='adrian' %}

And this is the best part. It didn't occur to me to use template tags to
utilize the reverse lookup, and I didn't even plan for it. Wow! Thank
you for impressing me once again!

As soon as it matures let's create a repository for reusable Django apps.

Thanks,

Eugene

limodou

unread,
Apr 6, 2006, 11:03:54 PM4/6/06
to django-d...@googlegroups.com

Wow, another amazing idea.

> Thanks,
>
> Eugene

Eugene Lazutkin

unread,
Apr 6, 2006, 11:31:58 PM4/6/06
to django-d...@googlegroups.com
limodou wrote:
>>
>> As soon as it matures let's create a repository for reusable Django apps.
>
> Wow, another amazing idea.

This is actually how it all started. Many people in Django community
implemented really good applications (hugo, sune, limodou, ...) but in
order to reuse them we have to modify their code customizing them for
our web sites. For example on my web site there are private apps, which
reuse some of my blog components. The easiest way to reuse them was ...
to copy them to a different location with slight modifications, so they
will not clash with the existing instances and produce different URLs. I
don't think this is a proper solution.

While many problems can be solved with existing Django facilities + a
healthy dose of discipline and conventions (e.g., use externally
specified db_table, so a user can assign different tables for different
instances of a model), the reverse URL lookup required a support from
Django. It looks like we have it now. If we resolve the missing parts,
we can have reusable applications, which can be easily installed and
integrated in Django-powered web sites.

What is missing? The convention for database table names assignment is
missing of course. Anything else? i18n-related parameters? The way to
specify custom parameters? How to instantiate several instances of the
same app? How to package an app? Can we reuse Python Eggs for that? Can
Paste help us? I have more questions than answers, but now I can see the
light at the end of the tunnel.

Thanks,

Eugene

medhat

unread,
May 2, 2006, 12:51:15 PM5/2/06
to Django developers
Adrian Holovaty wrote:
> On the plane from London to Chicago yesterday, I implemented something
> that's been discussed on this list lately -- "reverse" URL creation.
>
> I've attached a new urlresolvers.py to this e-mail. It's intended to
> replace the one in django/core, and it works with magic-removal only.
> (To use it with trunk, just replace the import line at the top to
> import Http404 from django.core.exceptions instead of django.http.)
> I've also attached unit tests.
>
> [...]

>
> Thoughts?
>
> Adrian
>
> --
> Adrian Holovaty
> holovaty.com | djangoproject.com
>

Hi,

Is there any reason this is not added to the repository?

--
Thanks!
Medhat

Adrian Holovaty

unread,
May 2, 2006, 1:06:52 PM5/2/06
to django-d...@googlegroups.com
On 5/2/06, medhat <medhat...@gmail.com> wrote:
> Is there any reason this is not added to the repository?

We did a feature-freeze for magic-removal for a while, but, now that
it's been merged, I can get back to work on this.

SmileyChris

unread,
May 16, 2006, 12:31:09 AM5/16/06
to Django developers
I look forwards to the addition of this...

Reply all
Reply to author
Forward
0 new messages