How to prevent basic Django inline strings from being autosafe

Django Basic Inlines app renders a predefined template from pseudo-HTML syntax based on the app / model / id combination. For example, if you are writing a blog post, you can insert an image that was saved in your image model:

# In the admin
This is the body of my post.

<inline type="media.image" id="1" class="full">


The template then accepts a filter render_inlines

that requires labeling safe

in order to render the HTML correctly:

# Template
{{ post.body|render_inlines|safe }}


But even with the safe

filter, it still escapes HTML by generating &lt;p&gt;&lt;img src="..."&gt;&lt;p&gt;

in source.

According to the docs, the filter should be used mark_safe

to prevent auto-protection at the filter level, but the function inlines


already using mark_safe


Is there something needed in Django 1.4 to stop auto-protection at the custom filter level? I cannot get rid of this auto-protection, either on

I tried using autoescape=None

which didn't help either.


source to share

3 answers

I support fork of Inline app. Richard contacted me about this issue and I was able to trace it back to BeautifulSoup and not Django.

The problem was that the BeautifulSoup method was being replaceWith()

used to replace inline markup with a rendered template. The result render_to_string()

is, of course, a string. When it replaceWith()

receives a string, it turns it into NavigableString

. Since BeautifulSoup expects to NavigbleString

be a string, it assumes they are unsafe and avoids any HTML characters. The result is that the value returned by the Inline function inlines()

had an &gt;

and in it &lt;

, not an <

and >


I didn't notice this issue in Django 1.3. When I looked, BeautifulSoup was indeed returning escaped HTML. Django's template filter |safe

was supposed to remove unnecessary HTML. In Django 1.4, this is no longer the case. (And he shouldn't do that!)

My fix for this is to parse the input value with BeautifulSoup and use BeautifulSoup to find all of the inline markup as before. Instead of using BeautifulSoup's method replaceWith()

to replace inline markup with inline template, I now just use Python plain old str.replace()

. It seems a bit lame to me, converting the parsed soup back to a string and then performing a string change. But it works. I'm kind of tempted to just do away with BeautifulSoup and find inline markup with regular expressions, but we all know how that ends up . If anyone has a better idea, I'm all ears!

The fix was originally implemented in this commit . I improved it in the next commit, but apparently StackOverflow allows me to post a maximum of two links, so you'll have to find that yourself!



Another solution for this is to turn the new code into a BeautifulSoup object and replaceWith the specified object. So the beautiful soup seems to behave the right way.

This gives you the escaped html:

soup = BeautifulSoup(html_doc)
body = soup.body
new_html = """<p> this is some deap code</p><a href="#">Pointless even</a>"""


This gives you html unescapped:

soup = BeautifulSoup(html_doc)
body = soup.body
new_html = """<p> this is some deap code</p><a href="#">Pointless even</a>"""




This is because of render_to_string

here . Go to inlines/app_model.html

and inlines/default.html

and add |safe

after having content variables there.



All Articles