Fixed #18974 - Warned against using models.permalink

Thanks dstufft for the draft patch.
This commit is contained in:
Tim Graham 2012-11-20 07:15:16 -05:00
parent 891c530624
commit 0e3690d230
5 changed files with 43 additions and 40 deletions

View File

@ -482,9 +482,13 @@ For example::
return "/people/%i/" % self.id return "/people/%i/" % self.id
(Whilst this code is correct and simple, it may not be the most portable way to (Whilst this code is correct and simple, it may not be the most portable way to
write this kind of method. The :func:`permalink() decorator <permalink>`, write this kind of method. The :func:`~django.core.urlresolvers.reverse`
documented below, is usually the best approach and you should read that section function is usually the best approach.)
before diving into code implementation.)
For example::
def get_absolute_url(self):
return reverse('people.views.details', args=[str(self.id)])
One place Django uses ``get_absolute_url()`` is in the admin app. If an object 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 defines this method, the object-editing page will have a "View on site" link
@ -529,11 +533,19 @@ in ``get_absolute_url()`` and have all your other code call that one place.
The ``permalink`` decorator The ``permalink`` decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
The way we wrote ``get_absolute_url()`` above is a slightly violation of the .. warning::
DRY principle: the URL for this object is defined both in the URLconf file and
in the model.
You can decouple your models from the URLconf using the ``permalink`` decorator: The ``permalink`` decorator is no longer recommended. You should use
:func:`~django.core.urlresolvers.reverse` in the body of your
``get_absolute_url`` method instead.
In early versions of Django, there wasn't an easy way to use URLs defined in
URLconf file inside :meth:`~django.db.models.Model.get_absolute_url`. That
meant you would need to define the URL both in URLConf and
:meth:`~django.db.models.Model.get_absolute_url`. The ``permalink`` decorator
was added to overcome this DRY principle violation. However, since the
introduction of :func:`~django.core.urlresolvers.reverse` there is no
reason to use ``permalink`` any more.
.. function:: permalink() .. function:: permalink()
@ -544,14 +556,14 @@ correct URL, with all parameters substituted in the correct positions.
The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url` The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url`
template tag and a high-level wrapper for the template tag and a high-level wrapper for the
:func:`django.core.urlresolvers.reverse()` function. :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::
(r'^people/(\d+)/$', 'people.views.details'), (r'^people/(\d+)/$', 'people.views.details'),
...your model could have a :meth:`~django.db.models.Model.get_absolute_url()` ...your model could have a :meth:`~django.db.models.Model.get_absolute_url`
method that looked like this:: method that looked like this::
from django.db import models from django.db import models

View File

@ -262,11 +262,11 @@ Taking care in ``get_absolute_url()``
URLs can only contain ASCII characters. If you're constructing a URL from URLs can only contain ASCII characters. If you're constructing a URL from
pieces of data that might be non-ASCII, be careful to encode the results in a pieces of data that might be non-ASCII, be careful to encode the results in a
way that is suitable for a URL. The ``django.db.models.permalink()`` decorator way that is suitable for a URL. The :func:`~django.core.urlresolvers.reverse`
handles this for you automatically. function handles this for you automatically.
If you're constructing a URL manually (i.e., *not* using the ``permalink()`` If you're constructing a URL manually (i.e., *not* using the ``reverse()``
decorator), you'll need to take care of the encoding yourself. In this case, function), you'll need to take care of the encoding yourself. In this case,
use the ``iri_to_uri()`` and ``urlquote()`` functions that were documented use the ``iri_to_uri()`` and ``urlquote()`` functions that were documented
above_. For example:: above_. For example::

View File

@ -178,25 +178,17 @@ whether a view would raise a ``Http404`` error before redirecting to it::
return HttpResponseRedirect('/') return HttpResponseRedirect('/')
return response return response
permalink()
-----------
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.
get_script_prefix() get_script_prefix()
------------------- -------------------
.. function:: get_script_prefix() .. function:: get_script_prefix()
Normally, you should always use :func:`~django.core.urlresolvers.reverse` or Normally, you should always use :func:`~django.core.urlresolvers.reverse` to
:func:`~django.db.models.permalink` to define URLs within your application. define URLs within your application. However, if your application constructs
However, if your application constructs part of the URL hierarchy itself, you part of the URL hierarchy itself, you may occasionally need to generate URLs.
may occasionally need to generate URLs. In that case, you need to be able to In that case, you need to be able to find the base URL of the Django project
find the base URL of the Django project within its Web server within its Web server (normally, :func:`~django.core.urlresolvers.reverse`
(normally, :func:`~django.core.urlresolvers.reverse` takes care of this for takes care of this for you). In that case, you can call
you). In that case, you can call ``get_script_prefix()``, which will return the ``get_script_prefix()``, which will return the script prefix portion of the URL
script prefix portion of the URL for your Django project. If your Django for your Django project. If your Django project is at the root of its web
project is at the root of its Web server, this is always ``"/"``. server, this is always ``"/"``.

View File

@ -552,12 +552,11 @@ layers where URLs are needed:
* In templates: Using the :ttag:`url` template tag. * In templates: Using the :ttag:`url` template tag.
* In Python code: Using the :func:`django.core.urlresolvers.reverse()` * In Python code: Using the :func:`django.core.urlresolvers.reverse`
function. function.
* In higher level code related to handling of URLs of Django model instances: * 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 The :meth:`~django.db.models.Model.get_absolute_url` method.
:func:`django.db.models.permalink` decorator.
Examples Examples
-------- --------
@ -622,10 +621,10 @@ view::
) )
This is completely valid, but it leads to problems when you try to do reverse This is completely valid, but it leads to problems when you try to do reverse
URL matching (through the :func:`~django.db.models.permalink` decorator or the URL matching (through the :func:`~django.core.urlresolvers.reverse` function
:ttag:`url` template tag). Continuing this example, if you wanted to retrieve or the :ttag:`url` template tag). Continuing this example, if you wanted to
the URL for the ``archive`` view, Django's reverse URL matcher would get retrieve the URL for the ``archive`` view, Django's reverse URL matcher would
confused, because *two* URL patterns point at that view. get confused, because *two* URL patterns point at that view.
To solve this problem, Django supports **named URL patterns**. That is, you can To solve this problem, Django supports **named URL patterns**. That is, you can
give a name to a URL pattern in order to distinguish it from other patterns give a name to a URL pattern in order to distinguish it from other patterns
@ -724,7 +723,7 @@ the fully qualified name into parts, and then tries the following lookup:
render a template. render a template.
The current application can also be specified manually as an argument The current application can also be specified manually as an argument
to the :func:`django.core.urlresolvers.reverse()` function. to the :func:`django.core.urlresolvers.reverse` function.
3. If there is no current application. Django looks for a default 3. If there is no current application. Django looks for a default
application instance. The default application instance is the instance application instance. The default application instance is the instance

View File

@ -1,3 +1,4 @@
from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
@ -14,9 +15,8 @@ class Artist(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
@models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('artist_detail', (), {'pk': self.id}) return reverse('artist_detail', kwargs={'pk': self.id})
@python_2_unicode_compatible @python_2_unicode_compatible
class Author(models.Model): class Author(models.Model):