我正在尝试在Django中实现一个WikiLink模板过滤器,它根据页面的存在情况查询数据库模型以提供不同的响应,与Wikipedia的红色链接相同。过滤器不会引发错误,而是对输入没有任何作用。
WikiLink 定义为:[[ThisIsAWikiLink | This is the alt text]]
这是一个不查询数据库的工作示例:
from django import template
from django.template.defaultfilters import stringfilter
from sites.wiki.models import Page
import re
register = template.Library()
@register.filter
@stringfilter
def wikilink(value):
return re.sub(r'\[\[ ?(.*?) ?\| ?(.*?) ?\]\]', r'<a href="/Sites/wiki/\1">\2</a>', value)
wikilink.is_safe = True
输入(value
)是一个多行字符串,包含HTML和许多WikiLink。
预期输出将[[ThisIsAWikiLink | This is the alt text]]
替换为
<a href="/Sites/wiki/ThisIsAWikiLink">This is the alt text</a>
或:
<a href="/Sites/wiki/ThisIsAWikiLink/edit" class="redlink">This is the alt text</a>
并返回值。
这是非工作代码(为回应评论/答案而编辑):
from django import template
from django.template.defaultfilters import stringfilter
from sites.wiki.models import Page
import re
register = template.Library()
@register.filter
@stringfilter
def wikilink(value):
m = re.match(r'\[\[ ?(.*?) ?\| ?(.*?) ?\]\]', value)
if(m):
page_alias = m.group(2)
page_title = m.group(3)
try:
page = Page.objects.get(alias=page_alias)
return re.sub(r'(\[\[)(.*)\|(.*)(\]\])', r'<a href="Sites\/wiki\/\2">\3</a>', value)
except Page.DoesNotExist:
return re.sub(r'(\[\[)(.*)\|(.*)(\]\])', r'<a href="Sites\/wiki\/\2\/edit" class="redlink">\3</a>', value)
else:
return value
wikilink.is_safe = True
代码需要做的是:
更新的问题是: 什么正则表达式(方法)可以返回一个python维基链接列表,可以更改并用于替换原始匹配(在更改后)。
编辑:
我想做这样的事情:
def wikilink(value):
regex = re.magic_method(r'\[\[ ?(.*?) ?\| ?(.*?) ?\]\]', value)
foreach wikilink in regex:
alias = wikilink.group(0)
text = wikilink.group(1)
if(alias exists in Page):
regex.sub("<a href="+alias+">"+ text +"</a>")
else:
regex.sub("<a href="+alias+" class='redlink'>"+ text +"</a>")
return value
答案 0 :(得分:4)
如果您的字符串除了wiki-link之外还包含其他文字,那么您的过滤器将无效,因为您使用的是re.match
而不是re.search
。 re.match
匹配字符串的开头。 re.search
匹配字符串中的任何位置。请参阅matching vs. searching。
此外,您的正则表达式使用贪婪的*
,因此如果一行包含多个wiki-links,它将无法工作。请改用*?
使其变得非贪婪:
re.search(r'\[\[(.*?)\|(.*?)\]\]', value)
编辑:
至于如何修复代码的提示,我建议您使用re.sub
with a callback。优点是:
这是一个关于实施的草图:
import re
WIKILINK_RE = re.compile(r'\[\[(.*?)\|(.*?)\]\]')
def wikilink(value):
def wikilink_sub_callback(match_obj):
alias = match_obj.group(1).strip()
text = match_obj.group(2).strip()
if(alias exists in Page):
class_attr = ''
else:
class_attr = ' class="redlink"'
return '<a href="%s"%s>%s</a>' % (alias, class_attr, text)
return WIKILINK_RE.sub(wikilink_sub_callback, value)
答案 1 :(得分:3)
这种问题很快就会出现在一小组单元测试中。
可以单独测试的过滤器片段(通过一些代码重构):
这可以帮助您找出出错的地方。你可能会发现你需要重新连接正则表达式来解释|。
周围的可选空格。此外,乍一看,您的过滤器看起来像是可以利用的。您声称结果是安全的,但您没有过滤脚本标签等恶意文本的替代文字。
答案 2 :(得分:1)
代码:
import re
def page_exists(alias):
if alias == 'ThisIsAWikiLink':
return True
return False
def wikilink(value):
if value == None:
return None
for alias, text in re.findall('\[\[\s*(.*?)\s*\|\s*(.*?)\s*\]\]',value):
if page_exists(alias):
value = re.sub('\[\[\s*%s\s*\|\s*%s\s*\]\]' % (alias,text), '<a href="/Sites/wiki/%s">%s</a>' % (alias, text),value)
else:
value = re.sub('\[\[\s*%s\s*\|\s*%s\s*\]\]' % (alias,text), '<a href="/Sites/wiki/%s/edit/" class="redtext">%s</a>' % (alias, text), value)
return value
示例结果:
>>> import wikilink
>>> wikilink.wikilink(None)
>>> wikilink.wikilink('')
''
>>> wikilink.wikilink('Test')
'Test'
>>> wikilink.wikilink('[[ThisIsAWikiLink | This is the alt text]]')
'<a href="/Sites/wiki/ThisIsAWikiLink">This is the alt text</a>'
>>> wikilink.wikilink('[[ThisIsABadWikiLink | This is the alt text]]')
'<a href="/Sites/wiki/ThisIsABadWikiLink/edit/" class="redtext">This is the alt text</a>'
>>> wikilink.wikilink('[[ThisIsAWikiLink | This is the alt text]]\n[[ThisIsAWikiLink | This is another instance]]')
'<a href="/Sites/wiki/ThisIsAWikiLink">This is the alt text</a>\n<a href="/Sites/wiki/ThisIsAWikiLink">This is another instance</a>'
>>> wikilink.wikilink('[[ThisIsAWikiLink | This is the alt text]]\n[[ThisIsAWikiLink | This is another instance]]')
一般评论:
我认为使用这种方法很快就会遇到性能问题。
答案 3 :(得分:0)
如果有人需要,这是工作代码:
from django import template
from django.template.defaultfilters import stringfilter
from sites.wiki.models import Page
import re
register = template.Library()
@register.filter
@stringfilter
def wikilink(value):
WIKILINK_RE = re.compile(r'\[\[ ?(.*?) ?\| ?(.*?) ?\]\]')
def wikilink_sub_callback(match_obj):
alias = match_obj.group(1).strip()
text = match_obj.group(2).strip()
class_attr = ''
try:
Page.objects.get(alias=alias)
except Page.DoesNotExist:
class_attr = ' class="redlink"'
return '<a href="%s"%s>%s</a>' % (alias, class_attr, text)
return WIKILINK_RE.sub(wikilink_sub_callback, value)
wikilink.is_safe = True
非常感谢所有答案!