Django中的提及/内部链接

1 投票
1 回答
1556 浏览
提问于 2025-05-01 04:36

我有一堆模型(可以理解为一些数据结构)。这些模型都有一个叫做 get_absolute_url 的方法和一个叫做 text 的字段。我想在 text 字段里做一些内部链接,就像维基百科那样。

维基百科的内部链接只指向其他页面。我需要链接到我所有的模型。

我可以为内部链接设定一个格式,然后把这个格式替换成一个固定的链接,但这其实不是个好主意,因为链接可能会改变。所以,最好的办法是直接用 get_absolute_url 来引用。

另一个选择是使用模板标签,把特定的格式转换成链接。

那么,这该怎么做呢?有没有已经实现过的开源项目可以参考?

暂无标签

1 个回答

2

我几天前也想解决这个问题,最后用了一种模板过滤器来实现。我的链接是相对地址,不是绝对地址,不过你可以很容易地调整一下,也可以修改正则表达式来匹配你想要的链接格式。

使用这个过滤器时,链接只在显示的时候查找,所以如果你的视图的URL发生了变化,它会自动通过reverse()来更新。

我还使用Markdown来处理我的描述字段,所以我让链接返回一个Markdown格式的链接,而不是HTML格式,不过你也可以调整这个。如果你使用Markdown,建议把这个过滤器放在最前面。

所以,要在模板中显示一个带有内部链接的描述文本字段,可以这样写:

{{ entity.description|internal_links|markdown }}

(想了解更多关于编写和注册过滤器的细节,可以查看Django文档关于自定义过滤器的部分。)

至于具体的过滤器,我是这样写的:

from django import template
from django.core.urlresolvers import reverse
from my.views import *

register = template.Library()

@register.filter
def internal_links(value):
    """
    Takes a markdown textfield, and filters
    for internal links in the format:

    {{film:alien-1979}}

    ...where "film" is the designation for a link type (model),
    and "alien-1979" is the slug for a given object

    NOTE: Process BEFORE markdown, as it will resolve
    to a markdown-formatted linked name:

    [Alien](http://opticalpodcast.com/cinedex/film/alien-1979/)

    :param value:
    :return:
    """
    try:
        import re
        pattern = '{{\S+:\S+}}'
        p = re.compile(pattern)
        #replace the captured pattern(s) with the markdown link
        return p.sub(localurl, value)
    except:
        # If the link lookup fails, just display the original text
        return value

def localurl(match):
    string = match.group()

    # Strip off the {{ and }}
    string = string[2:-2]

    # Separate the link type and the slug
    link_type, link_slug = string.split(":")
    link_view = ''

    # figure out what view we need to display
    # for the link type
    if(link_type == 'film'):
        link_view = 'film_detail'
    elif(link_type == 'person'):
        link_view = 'person_detail'
    else:
        raise Exception("Unknown link type.")

    link_url = reverse(link_view, args=(link_slug,))
    entity = get_object_or_404(Entity, slug=link_slug)
    markdown_link = "[" + entity.name + "](" + link_url + ")"

    return markdown_link

撰写回答