[Answered ]-Mentions/internal links in Django

2👍

I wanted to answer this same problem just a few days ago, and I did it with a template filter. My links are relative URLs, not absolute, but you could tweak that pretty easily, and you could also tweak the regex pattern to match whatever link markup you prefer.

Using the filter, the link is only looked up at display time, so if your view’s URL has changed, that should automatically update with the reverse() lookup.

I also use Markdown to process my description fields, so I make the link return a markdown-formatted link instead of HTML, but you could tweak that too. If you use Markdown, you’d want to put this filter first.

So to display a description TextField with internal links, in the template would be something like this:

{{ entity.description|internal_links|markdown }}

(See the Django docs on writing your own custom filters for more details on writing and registering filters.)

As for the specific filter itself, I did it like this:

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

Leave a comment