Browse files

Added section about URL reversion to URL mapper document.

  • Loading branch information...
1 parent 34a736b commit ec1aad1671bfbba7ef58e7477dd14d7add065838 @ramiro ramiro committed Oct 7, 2012
@@ -226,7 +226,7 @@ Hooking the wizard into a URLconf
Finally, we need to specify which forms to use in the wizard, and then
-deploy the new :class:`WizardView` object at an URL in the ````. The
+deploy the new :class:`WizardView` object at a URL in the ````. The
wizard's :meth:`as_view` method takes a list of your
:class:`~django.forms.Form` classes as an argument during instantiation::
@@ -494,12 +494,16 @@ defined. If it makes sense for your model's instances to each have a unique
URL, you should define ``get_absolute_url()``.
It's good practice to use ``get_absolute_url()`` in templates, instead of
-hard-coding your objects' URLs. For example, this template code is bad::
+hard-coding your objects' URLs. For example, this template code is bad:
+.. code-block:: html+django
<!-- BAD template code. Avoid! -->
<a href="/people/{{ }}/">{{ }}</a>
-This template code is much better::
+This template code is much better:
+.. code-block:: html+django
<a href="{{ object.get_absolute_url }}">{{ }}</a>
@@ -535,7 +539,9 @@ pattern name) and a list of position or keyword arguments and uses the URLconf
patterns to construct the correct, full URL. It returns a string for the
correct URL, with all parameters substituted in the correct positions.
-The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url` template tag and a high-level wrapper for the :func:`django.core.urlresolvers.reverse()` function.
+The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url`
+template tag and a high-level wrapper for the
+:func:`django.core.urlresolvers.reverse()` function.
An example should make it clear how to use ``permalink()``. Suppose your URLconf
contains a line such as::
@@ -997,7 +997,7 @@ refer to the name of the pattern in the ``url`` tag instead of using the
path to the view.
Note that if the URL you're reversing doesn't exist, you'll get an
-:exc:`^django.core.urlresolvers.NoReverseMatch` exception raised, which will
+:exc:`~django.core.urlresolvers.NoReverseMatch` exception raised, which will
cause your site to display an error page.
If you'd like to retrieve a URL without displaying it, you can use a slightly
@@ -8,8 +8,7 @@ reverse()
If you need to use something similar to the :ttag:`url` template tag in
-your code, Django provides the following function (in the
-:mod:`django.core.urlresolvers` module):
+your code, Django provides the following function:
.. function:: reverse(viewname, [urlconf=None, args=None, kwargs=None, current_app=None])
@@ -59,15 +58,15 @@ You can use ``kwargs`` instead of ``args``. For example::
.. note::
- The string returned by :meth:`~django.core.urlresolvers.reverse` is already
+ The string returned by ``reverse()`` is already
:ref:`urlquoted <uri-and-iri-handling>`. For example::
>>> reverse('cities', args=[u'Orléans'])
Applying further encoding (such as :meth:`~django.utils.http.urlquote` or
- ``urllib.quote``) to the output of :meth:`~django.core.urlresolvers.reverse`
- may produce undesirable results.
+ ``urllib.quote``) to the output of ``reverse()`` may produce undesirable
+ results.
@@ -94,9 +93,8 @@ URLConf is loaded. Some common cases where this function is necessary are:
-The :func:`django.core.urlresolvers.resolve` function can be used for
-resolving URL paths to the corresponding view functions. It has the
-following signature:
+The ``resolve()`` function can be used for resolving URL paths to the
+corresponding view functions. It has the following signature:
.. function:: resolve(path, urlconf=None)
@@ -184,7 +182,7 @@ whether a view would raise a ``Http404`` error before redirecting to it::
-The :func:`django.db.models.permalink` decorator is useful for writing short
+The :func:`~django.db.models.permalink` decorator is useful for writing short
methods that return a full URL path. For example, a model's
``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more.
@@ -421,9 +421,9 @@ options to views.
Passing extra options to ``include()``
-Similarly, you can pass extra options to ``include()``. When you pass extra
-options to ``include()``, *each* line in the included URLconf will be passed
-the extra options.
+Similarly, you can pass extra options to :func:`~django.conf.urls.include`.
+When you pass extra options to ``include()``, *each* line in the included
+URLconf will be passed the extra options.
For example, these two URLconf sets are functionally identical:
@@ -510,6 +510,103 @@ imported::
(r'^myview/$', ClassBasedView.as_view()),
+Reverse resolution of URLs
+A common need when working on a Django project is the possibility to obtain URLs
+in their final forms either for embedding in generated content (views and assets
+URLs, URLs shown to the user, etc.) or for handling of the navigation flow on
+the server side (redirections, etc.)
+It is strongly desirable not having to hard-code these URLs (a laborious,
+non-scalable and error-prone strategy) or having to devise ad-hoc mechanisms for
+generating URLs that are parallel to the design described by the URLconf and as
+such in danger of producing stale URLs at some point.
+In other words, what's needed is a DRY mechanism. Among other advantages it
+would allow evolution of the URL design without having to go all over the
+project source code to search and replace outdated URLs.
+The piece of information we have available as a starting point to get a URL is
+an identification (e.g. the name) of the view in charge of handling it, other
+pieces of information that necessarily must participate in the lookup of the
+right URL are the types (positional, keyword) and values of the view arguments.
+Django provides a solution such that the URL mapper is the only repository of
+the URL design. You feed it with your URLconf and then it can be used in both
+* Starting with a URL requested by the user/browser, it calls the right Django
+ view providing any arguments it might need with their values as extracted from
+ the URL.
+* Starting with the identification of the corresponding Django view plus the
+ values of arguments that would be passed to it, obtain the associated URL.
+The first one is the usage we've been discussing in the previous sections. The
+second one is what is known as *reverse resolution of URLs*, *reverse URL
+matching*, *reverse URL lookup*, or simply *URL reversing*.
+Django provides tools for performing URL reversing that match the different
+layers where URLs are needed:
+* In templates: Using the :ttag:`url` template tag.
+* In Python code: Using the :func:`django.core.urlresolvers.reverse()`
+ function.
+* In higher level code related to handling of URLs of Django model instances:
+ The :meth:`django.db.models.Model.get_absolute_url()` method and the
+ :func:`django.db.models.permalink` decorator.
+Consider again this URLconf entry::
+ from django.conf.urls import patterns, url
+ urlpatterns = patterns('',
+ #...
+ url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
+ #...
+ )
+According to this design, the URL for the archive corresponding to year *nnnn*
+is ``/articles/nnnn/``.
+You can obtain these in template code by using:
+.. code-block:: html+django
+ <a href="{% url 'news.views.year_archive' 2012 %}">2012 Archive</a>
+ {# Or with the year in a template context variable: #}
+ <ul>
+ {% for yearvar in year_list %}
+ <li><a href="{% url 'news.views.year_archive' yearvar %}">{{ yearvar }} Archive</a></li>
+ {% endfor %}
+ </ul>
+Or in Python code::
+ from django.core.urlresolvers import reverse
+ from django.http import HttpResponseRedirect
+ def redirect_to_year(request):
+ # ...
+ year = 2006
+ # ...
+ return HttpResponseRedirect(reverse('new.views.year_archive', args=(year,)))
+If, for some reason, it was decided that the URL where content for yearly
+article archives are published at should be changed then you would only need to
+change the entry in the URLconf.
+In some scenarios where views are of a generic nature, a many-to-one
+relationship might exist between URLs and views. For these cases the view name
+isn't a good enough identificator for it when it comes the time of reversing
+URLs. Read the next section to know about the solution Django provides for this.
.. _naming-url-patterns:
Naming URL patterns
@@ -689,9 +786,10 @@ URL namespaces and included URLconfs
URL namespaces of included URLconfs can be specified in two ways.
-Firstly, you can provide the application and :term:`instance namespace` as
-arguments to :func:`django.conf.urls.include()` when you construct your URL
-patterns. For example,::
+Firstly, you can provide the :term:`application <application namespace>` and
+:term:`instance <instance namespace>` namespaces as arguments to
+:func:`django.conf.urls.include()` when you construct your URL patterns. For
(r'^help/', include('', namespace='foo', app_name='bar')),
@@ -706,6 +804,15 @@ However, you can also ``include()`` a 3-tuple containing::
(<patterns object>, <application namespace>, <instance namespace>)
+For example::
+ help_patterns = patterns('',
+ url(r'^basic/$', ''),
+ url(r'^advanced/$', ''),
+ )
+ (r'^help/', include(help_patterns, 'bar', 'foo')),
This will include the nominated URL patterns into the given application and
instance namespace.
@@ -769,7 +769,7 @@ Use the ``django.test.client.Client`` class to make requests.
and a ``redirect_chain`` attribute will be set in the response object
containing tuples of the intermediate urls and status codes.
- If you had an url ``/redirect_me/`` that redirected to ``/next/``, that
+ If you had a URL ``/redirect_me/`` that redirected to ``/next/``, that
redirected to ``/final/``, this is what you'd see::
>>> response = c.get('/redirect_me/', follow=True)

0 comments on commit ec1aad1

Please sign in to comment.