【问题标题】:Django - mark only certain part of string / user input as safe?Django - 仅将字符串/用户输入的某些部分标记为安全?
【发布时间】:2015-01-16 10:32:00
【问题描述】:

用户文本输入如下:

Test 'post'. Post at 8:52 on Feb 3rd. /u/username created it.
This <a href="link">link</a> should not be displayed as a link.

在模板上显示用户输入时,我通过自定义过滤器发送它。这是自定义过滤器:

word_split_re = re.compile(r'(\s+)')

@register.filter
@stringfilter
def customUrlize(value):
    words = word_split_re.split(force_text(value))
    for i, b in enumerate(words):
        if b.startswith('/u/'):
            username = b[3:]
            if re.match("^[A-Za-z0-9_-]*$", username):
                b = "<a href='testLink'>" + b + "</a>"
                words[i] = mark_safe(b)
    return ''.join(words)

如您所见,我想要做的是以 '/u/' 开头的单词(并且只包含字母、数字、下划线和破折号)用

<a>

标签。使用当前过滤器,所有代码都被转义并显示为:

Test 'post'. Post at 8:52 on Feb 3rd. <a href='testLink'>/u/username</a> created it.
This <a href="link">link</a> should not be displayed as a link.

我想要的是正常显示文本,但 /u/username 是一个链接。

如果我尝试这样做:

return mark_safe(''.join(words))

然后它甚至显示

<a href="link">link</a>

作为链接与

/u/username

如何让它只显示

/u/username

作为链接?

编辑:我使用的是 Django 1.5。

在我的模板中,假设

comment

是一个

CharField

我这样显示评论:

{{ comment|customUrlize }}

【问题讨论】:

    标签: django django-templates django-template-filters


    【解决方案1】:

    除非您要保留文本中的某些其他格式,否则您可以在更改文本之前直接escape 文本。

    返回带有 & 符号、引号和尖括号的给定文本,这些文本经过编码以便在 HTML 中使用。输入首先通过force_text(),输出应用mark_safe()

    From the Django documentation

    所以这一行:

    words = word_split_re.split(force_text(value))
    

    变成这样:

    words = word_split_re.split(escape(value))
    

    完整的过滤器是:

    from django.utils.html import escape
    
    word_split_re = re.compile(r'(\s+)')
    
    @register.filter
    @stringfilter
    def customUrlize(value):
        words = word_split_re.split(escape(value)) 
        for i, b in enumerate(words):
            if b.startswith('/u/'):
                username = b[3:]
                if re.match("^[A-Za-z0-9_-]*$", username):
                    b = "<a href='testLink'>" + b + "</a>"
                    words[i] = mark_safe(b)
        return mark_safe(''.join(words))
    

    并且应该给:

    Test 'post'. Post at 8:52 on Feb 3rd. <a href='testLink'>/u/username</a> created it.
    This &lt;a href="link"&gt;link&lt;/a&gt; should not be displayed as a link.
    

    呈现为:

    测试“发布”。 2 月 3 日 8 点 52 分发帖。 /u/username 创建了它。 此链接不应显示为链接。

    【讨论】:

    • hm,您能否再次确认您显示的呈现文本正是它为您呈现的内容?我复制粘贴了您的过滤器,但对我来说,它仍然呈现“/u/username”而不是实际链接。即使在应用了我的自定义过滤器之后,似乎 Django 也会自动转义文本。如果有帮助,我正在使用 Django 1.5。
    • 这就是应该呈现的,我不明白这个问题。如果它没有转义 &lt; 它是否按预期工作?
    • 渲染的文本对我来说如下所示:“测试'post'。2 月 3 日 8:52 发布。/u/username 创建了它. 此 <a href="link">link</a> 不应显示为链接。"我希望将“/u/username”呈现为实际链接,而不是在 html 中显示“”。我说的现在更有意义了吗?
    • 另外,对不起,当我说“它仍然呈现“/u/username”时,我在最初的评论中的意思是“它仍然会呈现作为“/u/username
    • 远程也不行。听起来它正在显示一个链接。
    【解决方案2】:

    根据您的需要,这可能无济于事,但您可以将字符串一分为二,并在模板中只用 |safe 标记第一个。

    例如:

    a = "Test 'post'. Post at 8:52 on Feb 3rd. <a href='testLink'>/u/username</a> created it. This <a href='link'>link</a> should not be displayed as a link."
    
    b = a.split('it.')
    

    然后将其传递给模板

    'string1': b[0]
    'string2': b[1]
    

    或其他,然后在模板中{{string1|safe}} &lt;br&gt; {{string2}}

    输出将如您所愿。没有“它”,当然。但这很容易解决。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 2017-08-30
      相关资源
      最近更新 更多