Slightly rewrite @permalink and get_absolute_url() documentation.

Part 2 of the model instance documentation changes. Slightly tidied up
get_absolute_url() and @permalink documentation to collapse some of the
earlier versions into a preferred learning order. I'm still not
amazingly happy with this, but larger rewrites are needed to the URLconf
stuff across a few files before I can get it into the most natural
order, I suspect. That's a slightly longer-term project.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16702 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2011-08-28 02:05:32 +00:00
parent a0eb58e90b
commit 77189afb7f
1 changed files with 58 additions and 40 deletions

View File

@ -414,60 +414,82 @@ using ``__str__()`` like this::
.. method:: Model.get_absolute_url() .. method:: Model.get_absolute_url()
Define a ``get_absolute_url()`` method to tell Django how to calculate the Define a ``get_absolute_url()`` method to tell Django how to calculate the
canonical URL for an object. For example:: canonical URL for an object. To callers, this method should appear to return a
string that can be used to refer to the object over HTTP.
For example::
def get_absolute_url(self): def get_absolute_url(self):
return "/people/%i/" % self.id return "/people/%i/" % self.id
Django uses this in its admin interface. If an object defines (Whilst this code is correct and simple, it may not be the most portable way to
``get_absolute_url()``, the object-editing page will have a "View on site" write this kind of method. The :func:`permalink() decorator <permalink>`,
link that will jump you directly to the object's public view, according to documented below, is usually the best approach and you should read that section
before diving into code implementation.)
One place Django uses ``get_absolute_url()`` is in the admin app. If an object
defines this method, the object-editing page will have a "View on site" link
that will jump you directly to the object's public view, as given by
``get_absolute_url()``. ``get_absolute_url()``.
Also, a couple of other bits of Django, such as the :doc:`syndication feed Similarly, a couple of other bits of Django, such as the :doc:`syndication feed
framework </ref/contrib/syndication>`, use ``get_absolute_url()`` as a framework </ref/contrib/syndication>`, use ``get_absolute_url()`` when it is
convenience to reward people who've defined the method. 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 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::
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a> <a href="/people/{{ object.id }}/">{{ object.name }}</a>
But this template code is good:: This template code is much better::
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a> <a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
The logic here is that if you change the URL structure of your objects, even
for something simple such as correcting a spelling error, you don't want to
have to track down every place that the URL might be created. Specify it once,
in ``get_absolute_url()`` and have all your other code call that one place.
.. note:: .. note::
The string you return from ``get_absolute_url()`` must contain only ASCII The string you return from ``get_absolute_url()`` **must** contain only
characters (required by the URI spec, `RFC 2396`_) that have been ASCII characters (required by the URI specfication, `RFC 2396`_) and be
URL-encoded, if necessary. Code and templates using ``get_absolute_url()`` URL-encoded, if necessary.
should be able to use the result directly without needing to do any
further processing. You may wish to use the Code and templates calling ``get_absolute_url()`` should be able to use the
result directly without any further processing. You may wish to use the
``django.utils.encoding.iri_to_uri()`` function to help with this if you ``django.utils.encoding.iri_to_uri()`` function to help with this if you
are using unicode strings a lot. are using unicode strings containing characters outside the ASCII range at
all.
.. _RFC 2396: http://www.ietf.org/rfc/rfc2396.txt .. _RFC 2396: http://www.ietf.org/rfc/rfc2396.txt
The ``permalink`` decorator The ``permalink`` decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
The problem with the way we wrote ``get_absolute_url()`` above is that it The way we wrote ``get_absolute_url()`` above is a slightly violation of the
slightly violates the DRY principle: the URL for this object is defined both DRY principle: the URL for this object is defined both in the URLconf file and
in the URLconf file and in the model. in the model.
You can further decouple your models from the URLconf using the ``permalink`` You can decouple your models from the URLconf using the ``permalink`` decorator:
decorator:
.. function:: permalink() .. function:: permalink()
This decorator is passed the view function, a list of positional parameters and This decorator takes the name of a URL pattern (either a view name or a URL
(optionally) a dictionary of named parameters. Django then works out the correct pattern name) and a list of position or keyword arguments and uses the URLconf
full URL path using the URLconf, substituting the parameters you have given into patterns to construct the correct, full URL. It returns a string for the
the URL. For example, if your URLconf contained a line such as:: 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.
An example should make it clear how to use ``permalink()``. Suppose your URLconf
contains a line such as::
(r'^people/(\d+)/$', 'people.views.details'), (r'^people/(\d+)/$', 'people.views.details'),
...your model could have a ``get_absolute_url`` method that looked like this:: ...your model could have a :meth:`~django.db.models.Model.get_absolute_url()`
method that looked like this::
from django.db import models from django.db import models
@ -491,26 +513,22 @@ Similarly, if you had a URLconf entry that looked like::
Notice that we specify an empty sequence for the second parameter in this case, Notice that we specify an empty sequence for the second parameter in this case,
because we only want to pass keyword parameters, not positional ones. because we only want to pass keyword parameters, not positional ones.
In this way, you're tying the model's absolute path to the view that is used In this way, you're associating the model's absolute path with the view that is
to display it, without repeating the URL information anywhere. You can still used to display it, without repeating the view's URL information anywhere. You
use the ``get_absolute_url`` method in templates, as before. can still use the :meth:`~django.db.models.Model.get_absolute_url()` method in
templates, as before.
In some cases, such as the use of generic views or the re-use of In some cases, such as the use of generic views or the re-use of custom views
custom views for multiple models, specifying the view function may for multiple models, specifying the view function may confuse the reverse URL
confuse the reverse URL matcher (because multiple patterns point to matcher (because multiple patterns point to the same view). For that case,
the same view). Django has :ref:`named URL patterns <naming-url-patterns>`. Using a named URL
pattern, it's possible to give a name to a pattern, and then reference the name
For that problem, Django has **named URL patterns**. Using a named rather than the view function. A named URL pattern is defined by replacing the
URL pattern, it's possible to give a name to a pattern, and then pattern tuple by a call to the ``url`` function)::
reference the name rather than the view function. A named URL
pattern is defined by replacing the pattern tuple by a call to
the ``url`` function)::
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
url(r'^people/(\d+)/$', url(r'^people/(\d+)/$', 'blog_views.generic_detail', name='people_view'),
'django.views.generic.list_detail.object_detail',
name='people_view'),
...and then using that name to perform the reverse URL resolution instead ...and then using that name to perform the reverse URL resolution instead
of the view name:: of the view name::