为了让项目更好维护,应当尽量减少硬编码,使用permalink能减少url硬编码。我们直接看下它的源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def permalink(func):
    """
    Decorator that calls urlresolvers.reverse() to return a URL using
    parameters returned by the decorated function "func".

    "func" should be a function that returns a tuple in one of the
    following formats:
        (viewname, viewargs)
        (viewname, viewargs, viewkwargs)
    """
    from django.core.urlresolvers import reverse

    @wraps(func)
    def inner(*args, **kwargs):
        bits = func(*args, **kwargs)
        return reverse(bits[0], None, *bits[1:3])
    return inner

由此不难看出,permalink实质是一个装饰器。 其实在我之前的yunfan项目中就用了permalink,主要是受‘django-basic-apps’的启发,很认真地看过这个项目的源码,感觉写得挺好看的。带领大家弄懂permalink的原理后,我们再来看看permalink在django-basic-apps的groups模块中的应用,如此一来将理论与实践结合。

好,废话不说,关于permalink,先看django官网解释:

  • This decorator takes the name of a URL pattern (either a view name or a URL 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.

balabala说了一堆,我们还是直接看例子吧:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#urls.py
(r'^people/(\d+)/$', 'people.views.details'),

#models.py
from django.db import models


@models.permalink
def get_absolute_url(self):
    return ('people.views.details', [str(self.id)])
#get_absolute_url一般是某个类的方法

当你的url更复杂时,你会更感激permalink,像这样

1
(r'/archive/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', archive_view)

这是很常见的博客的url.
对应的model

1
2
3
4
5
6
@models.permalink
def get_absolute_url(self):
    return ('archive_view', (), {
        'year': self.created.year,
        'month': self.created.strftime('%m'),
        'day': self.created.strftime('%d')})

到这里其实已经很明了了。archive_view是url函数,permalink会根据archive_view指向的模式以及提供的参数字典反向解析出url,并且返回,至此,一切搞定。
如此一来,抽象地看,对象的url似乎是对象的方法,维护起来十分方便。 在模板里只要酱紫用就行:

1
{% archive.get_absolute_url %} 

多么清晰不是~

好的,我们继续看下permalink在django-basic-apps的groups模块中的应用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#urls.py
GROUP_URL = r'(?P<slug>[-\w]+)/'
urlpatterns = patterns('basic.groups.views.groups',
    ....
    url(r'^%s$' % GROUP_URL, 'group_detail', name='group'),
)

#models.py
class Group(models.Model):
    """ Group model """
    title = models.CharField(blank=False, max_length=255)
    slug = models.SlugField(unique=True, help_text="Used for the Group URL: http://example.com/groups/the-club/")
    ....

    @permalink
    def get_absolute_url(self):
        return ('groups:group', None, {'slug': self.slug})

#group_list.html
<li><a href="{{ group.get_absolute_url }}">{{ group }}</a></li>

良好的代码便是最好的注释,相信大家不须我解释都看懂啦~