Added section about URL reversion to URL mapper document.
This commit is contained in:
parent
34a736b752
commit
ec1aad1671
|
@ -226,7 +226,7 @@ Hooking the wizard into a URLconf
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
Finally, we need to specify which forms to use in the wizard, and then
|
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
|
wizard's :meth:`as_view` method takes a list of your
|
||||||
:class:`~django.forms.Form` classes as an argument during instantiation::
|
: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()``.
|
URL, you should define ``get_absolute_url()``.
|
||||||
|
|
||||||
It's good practice to use ``get_absolute_url()`` in templates, instead of
|
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! -->
|
<!-- BAD template code. Avoid! -->
|
||||||
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
|
<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>
|
<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
|
patterns to construct the correct, full URL. It returns a string for the
|
||||||
correct URL, with all parameters substituted in the correct positions.
|
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
|
An example should make it clear how to use ``permalink()``. Suppose your URLconf
|
||||||
contains a line such as::
|
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.
|
path to the view.
|
||||||
|
|
||||||
Note that if the URL you're reversing doesn't exist, you'll get an
|
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.
|
cause your site to display an error page.
|
||||||
|
|
||||||
If you'd like to retrieve a URL without displaying it, you can use a slightly
|
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
|
If you need to use something similar to the :ttag:`url` template tag in
|
||||||
your code, Django provides the following function (in the
|
your code, Django provides the following function:
|
||||||
:mod:`django.core.urlresolvers` module):
|
|
||||||
|
|
||||||
.. function:: reverse(viewname, [urlconf=None, args=None, kwargs=None, current_app=None])
|
.. 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::
|
.. 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::
|
:ref:`urlquoted <uri-and-iri-handling>`. For example::
|
||||||
|
|
||||||
>>> reverse('cities', args=[u'Orléans'])
|
>>> reverse('cities', args=[u'Orléans'])
|
||||||
'.../Orl%C3%A9ans/'
|
'.../Orl%C3%A9ans/'
|
||||||
|
|
||||||
Applying further encoding (such as :meth:`~django.utils.http.urlquote` or
|
Applying further encoding (such as :meth:`~django.utils.http.urlquote` or
|
||||||
``urllib.quote``) to the output of :meth:`~django.core.urlresolvers.reverse`
|
``urllib.quote``) to the output of ``reverse()`` may produce undesirable
|
||||||
may produce undesirable results.
|
results.
|
||||||
|
|
||||||
reverse_lazy()
|
reverse_lazy()
|
||||||
--------------
|
--------------
|
||||||
|
@ -94,9 +93,8 @@ URLConf is loaded. Some common cases where this function is necessary are:
|
||||||
resolve()
|
resolve()
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The :func:`django.core.urlresolvers.resolve` function can be used for
|
The ``resolve()`` function can be used for resolving URL paths to the
|
||||||
resolving URL paths to the corresponding view functions. It has the
|
corresponding view functions. It has the following signature:
|
||||||
following signature:
|
|
||||||
|
|
||||||
.. function:: resolve(path, urlconf=None)
|
.. function:: resolve(path, urlconf=None)
|
||||||
|
|
||||||
|
@ -184,7 +182,7 @@ whether a view would raise a ``Http404`` error before redirecting to it::
|
||||||
permalink()
|
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
|
methods that return a full URL path. For example, a model's
|
||||||
``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more.
|
``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more.
|
||||||
|
|
||||||
|
|
|
@ -421,9 +421,9 @@ options to views.
|
||||||
Passing extra options to ``include()``
|
Passing extra options to ``include()``
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
Similarly, you can pass extra options to ``include()``. When you pass extra
|
Similarly, you can pass extra options to :func:`~django.conf.urls.include`.
|
||||||
options to ``include()``, *each* line in the included URLconf will be passed
|
When you pass extra options to ``include()``, *each* line in the included
|
||||||
the extra options.
|
URLconf will be passed the extra options.
|
||||||
|
|
||||||
For example, these two URLconf sets are functionally identical:
|
For example, these two URLconf sets are functionally identical:
|
||||||
|
|
||||||
|
@ -510,6 +510,103 @@ imported::
|
||||||
(r'^myview/$', ClassBasedView.as_view()),
|
(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:
|
||||||
|
|
||||||
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.
|
URL namespaces of included URLconfs can be specified in two ways.
|
||||||
|
|
||||||
Firstly, you can provide the application and :term:`instance namespace` as
|
Firstly, you can provide the :term:`application <application namespace>` and
|
||||||
arguments to :func:`django.conf.urls.include()` when you construct your URL
|
:term:`instance <instance namespace>` namespaces as arguments to
|
||||||
patterns. For example,::
|
:func:`django.conf.urls.include()` when you construct your URL patterns. For
|
||||||
|
example,::
|
||||||
|
|
||||||
(r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')),
|
(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>)
|
(<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
|
This will include the nominated URL patterns into the given application and
|
||||||
instance namespace.
|
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
|
and a ``redirect_chain`` attribute will be set in the response object
|
||||||
containing tuples of the intermediate urls and status codes.
|
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::
|
redirected to ``/final/``, this is what you'd see::
|
||||||
|
|
||||||
>>> response = c.get('/redirect_me/', follow=True)
|
>>> response = c.get('/redirect_me/', follow=True)
|
||||||
|
|
Loading…
Reference in New Issue