Legend:

<div style="background-color: #ccc; padding: 0.3em 0.4em"><strong>Summary:</strong> get_absolute_url() is poorly defined and poorly named. It's too late to fix it for Django 1.0, but we should completely re-think it for Django 1.1.</div>

5

<div style="background-color: #ccc; padding: 0.3em 0.4em"><strong>Summary:</strong> get_absolute_url() is poorly defined and poorly named. It's too late to fix it for Django 1.0, but we should re-think it for Django 1.1.</div>

6

6

}}}

7

7

8

This page is a work in progress - I'm still figuring out the extent of the problem before I start working out the solution.

8

This page is a work in progress - I'm still figuring out the extent of the problem before I start working out a solution.

It's often useful for a model to "know" it's URL. This is especially true for sites that follow RESTful principles, where any entity within the site should have one and only one canonical URL.

13

13

14

It's also useful to keep URL logic in the same place as much as possible. Django's {% url %} template tag and reverse() function solve a slightly different problem - they resolve URLs for view functions, not for individual model objects, and treat the URLconf as the single point of truth for URLs. {% url "profile-view" user.id %} isn't as pragmatic as {{ user.get_absolute_url }}, since if we change the profile-view to take a username instead of a user ID in the URL we'll have to go back and update all of our templates.

14

It's also useful to keep URL logic in the same place as much as possible. Django's {% url %} template tag and reverse() function solve a slightly different problem - they resolve URLs for view functions, not for individual model objects, and treat the URLconf as the single point of truth for URLs. {% url myapp.views.profile user.id %} isn't as pragmatic as {{ user.get_absolute_url }}, since if we change the profile-view to take a username instead of a user ID in the URL we'll have to go back and update all of our templates.

15

15

16

16

Being able to get the URL for a model is also useful outside of the template system. Django's admin, syndication and sitemaps modules all attempt to derive a URL for a model at various points, currently using the get_absolute_url method.

Unfortunately, get_absolute_url is mis-named. An "absolute" URL should be expected to include the protocol and domain, but in most cases get_absolute_url just returns the path. It was proposed to rename get_absolute_url to get_url_path, but this doesn't make sense either as some objects DO return a full URL from get_absolute_url (and in fact some places in Django check to see if the return value starts with http:// and behave differently as a result).

21

21

22

From this, we can derive that there are actually two important URLs for a given model:

22

From this, we can derive that there are actually two important URL parts for a given model:

23

23

24

24

1. The full URL, including protocol and domain. This is needed for the following cases:

Finally, it's important that places that use get_absolute_url (such as the admin, sitemaps, syndication etc) always provide an over-ridable alternative. Syndication feeds may wish to include extra hit-tracking material on URLs, admin sites may wish to link to staging or production depending on other criteria etc. At the moment some but not all of these tools provide over-riding mechanisms, but without any consistency as to what they are called or how they work.

38

39

It bares repeating that the problem of turning a path returned by get_absolute_url in to a full URL is a very real one: Django actually solves it in a number of places, each one taking a slightly different approach, none of which are really ideal. The fact that it's being solved multiple times and in multiple ways suggests a strong need for a single, reliable solution.