Allows for in internal link markup to be saved inside markdown-formatted Textfield entries.
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.
You could tweak the regex pattern to match whatever link markup you prefer. 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.)
Written for my own website, and a basic version was shared as the answer to this Stack Overflow question.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | 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 searches for internal links in the format:
{{film:alien-1979}}
...where "film" is the designation for a model,
and "alien-1979" is the slug for a given object
NOTE: Process BEFORE markdown
If it is inside a markdown link,
it will resolve with the link text as intended:
[the first Alien movie]({{film:alien-1979}})
[the first Alien movie](/cinedex/film/alien-1979/)
If it is by itself, it will resolve to a linked name:
{{film:alien-1979}}
[Alien (1979)](/cinedex/film/alien-1979/)
:param value:
:return:
"""
try:
import re
# Pattern(s) inside a markdown link first
# e.g. [link text here]({{film:alien-1979}})
pattern = '\[.+\]\({{\S+:\S+}}\)'
p = re.compile(pattern)
text_linked = p.sub(localurl_markdown, value)
# After we replace those, find pattern(s) by itself
# e.g. {{film:alien-1979}}
pattern = '{{\S+:\S+}}'
p = re.compile(pattern)
#replace the captured pattern(s) with the new markdown link
return p.sub(localurl, text_linked)
except:
# Link lookups fail individually, but just in case there's
# some massive failure, just display the original text
return value
def localurlpattern(string):
# Strip off the {{ and }}
string = string[2:-2]
# Separate the link type and the slug
link_type, link_slug = string.split(":")
# figure out what view we need to display for the link_type
# Dictionary contains lookup as - link_type: viewname
# "viewname can be a string containing the Python path to the view object, a URL pattern name, or the callable view object."
# see https://docs.djangoproject.com/en/dev/ref/urlresolvers/#django.core.urlresolvers.reverse
link_types_views = {
'film': 'film_detail',
'person': 'person_detail',
'company': 'company_detail',
'term': 'term_detail',
}
# TODO: Maybe add error handling for a bad link_type, and try to look it up anyway
link_url = reverse(link_types_views[link_type], args=(link_slug,))
entity = get_object_or_404(Entity, slug=link_slug)
if link_type == 'film':
# If it's a film, the name should be in italics and include the year.
link_name = "*" + entity.name + "* (" + str(entity.release_date.year) + ")"
else:
link_name = entity.name
# Return name and link_url as part of a dictionary
link_dict = {'name': link_name, 'url': link_url}
return link_dict
def localurl(match):
string = match.group()
try:
link_dict = localurlpattern(string)
markdown_link = "[" + link_dict['name'] + "](" + link_dict['url'] + ")"
return markdown_link
except:
# The lookup has failed, so let's send back a notice that it's broken
print('Broken internal_links localurl to ' + string)
markdown_link = "[***[broken link to " + string[2:-2] + "]***](#" + string[2:-2] + ")"
return markdown_link
def localurl_markdown(match):
string = match.group()
markdown_link = ""
# Grab the link text and link pattern
p_obj = re.search(r'\[(.+)\]\(({{\S+:\S+}})\)', string)
try:
if p_obj:
link_dict = localurlpattern(p_obj.group(2))
markdown_link = "[" + p_obj.group(1) + "](" + link_dict['url'] + ")"
return markdown_link
except:
# The lookup has failed, so let's send back a notice that it's broken
print('Broken internal_links localurl_markdown to ' + string)
if p_obj:
markdown_link = "[" + p_obj.group(1) + " ***[broken link to " + p_obj.group(2)[2:-2] + "]***](#" + p_obj.group(2)[2:-2] + ")"
return markdown_link
else:
return string
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Please login first before commenting.