Django - mark only a specific part of a string / user input as safe?

User input looks like this:

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.

      

I send user input through a custom filter showing it on the template. This is a custom filter:

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)

      

As you can see what I want to do is wrap words starting with '/ u /' (And only letters, numbers, underscores and dashes) with

<a>

      

tag. With the current filter, all the code is escaped and it appears as:

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.

      

I want the text to display fine, but for / u / username was a link.

If I try to do:

return mark_safe(''.join(words))

      

then it displays even

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

      

as a reference along with

/u/username

      

How to make it display only

/u/username

      

how is the link?

Edit: I am using Django 1.5.

In my template, assuming

comment

      

is an

CharField

      

I am displaying the comment like this:

{{ comment|customUrlize }}

      

+3


source to share


2 answers


If there is no additional formatting in the text that you want to keep, you can just plain escape

text before changing it.

Returns the specified text, with ampersands, quotes, and angle brackets, encoded for use in HTML. The input is first passed through force_text()

, and the output is passed through mark_safe()

.

From Django documentation

So this line:

words = word_split_re.split(force_text(value))

      

Becomes as follows:

words = word_split_re.split(escape(value))

      



Full filter:

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))

      

And must give:

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.

      

which displays as:

Check "message". Posted at 8:52 am on February 3rd. / u / username created it. This <a href = "link"> link </a> should not appear as a link.

+3


source


It might not help depending on your needs, but you can just split the string in half and in the template label only the first one with | safe.

For example:

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.')

      

Then just pass it to the template as



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

      

or whatever and then {{string1|safe}} <br> {{string2}}

in the template.

The output will be the way you wanted. Without this, of course. But this is easy to fix.

+1


source







All Articles