Commit ec1aad16 authored by Ramiro Morales's avatar Ramiro Morales
Browse files

Added section about URL reversion to URL mapper document.

parent 34a736b7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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 ``urls.py``. The
deploy the new :class:`WizardView` object at a URL in the ``urls.py``. The
wizard's :meth:`as_view` method takes a list of your
:class:`~django.forms.Form` classes as an argument during instantiation::

+9 −3
Original line number Diff line number Diff line
@@ -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/{{ object.id }}/">{{ object.name }}</a>

This template code is much better::
This template code is much better:

.. code-block:: html+django

    <a href="{{ object.get_absolute_url }}">{{ object.name }}</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::
+1 −1
Original line number Diff line number Diff line
@@ -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
+7 −9
Original line number Diff line number Diff line
@@ -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'])
        '.../Orl%C3%A9ans/'

    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.

reverse_lazy()
--------------
@@ -94,9 +93,8 @@ URLConf is loaded. Some common cases where this function is necessary are:
resolve()
---------

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::
permalink()
-----------

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.

+113 −6
Original line number Diff line number Diff line
@@ -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
directions:

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

Examples
--------

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
example,::

    (r'^help/', include('apps.help.urls', 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/$', 'apps.help.views.views.basic'),
        url(r'^advanced/$', 'apps.help.views.views.advanced'),
    )

    (r'^help/', include(help_patterns, 'bar', 'foo')),

This will include the nominated URL patterns into the given application and
instance namespace.

Loading