This short example shows how to store HTML in a model’s field, alter it and and show on page as processed HTML code.
Storing
You may use Charfield
or Textfield
, though the latter is preferaby. Foe example, django-tinymce‘s HTMLfield
is basically a Textfield
anyway.
Manipulation
I will be using Beautiful Soup 4 for this.
Task
In a text, look for the content in certain types of tags (e.g. <u>
) and find instances with the text from this tags. Add something to the original content of <u>
and remove the <u>
‘s themselves.
Source
For example, there are phrases and I want to insert <a>
tag with phrases’ links alongside each of them.
Phrases
The world was on fire and no one could save me but you.
Something 2
It’s strange what desire will make foolish people doPhrases are from Wicked Game by Chris Isaak, courtesy of his recent performance 🙂

Result
Phrases
The world was on fire and no one could save me but you. (link)
Something 2
It’s strange what desire will make foolish people do (link)
Method
def add_link_to_html(html_source):
soup = BeautifulSoup(html_source, "html.parser")
for unit in soup.find_all("a", {'class': 'katya_link'}):
unit.decompose()
phrases = set(soup.findAll("u"))
html_source = str(soup)
result = html_source.replace('<u>','').replace('</u>','').strip().replace('\n', ' ').replace('\r', '')
for index, original in enumerate(phrases):
just_text = str(original.get_text()).strip()
original_str = str(original).replace('<u>', '').replace('</u>', '').strip()
try:
phrase_item, created = Phrase.objects.get_or_create(name=just_text)
phrase_item_any_link = phrase_item.any_link
if phrase_item_any_link:
linkd_phrase = '<a class="katya_link" href="%s"><img src="/static/image/link.png"></a>%s' % (
phrase_item_any_link, original_str)
else:
linkd_phrase = original_str
except Exception as e:
linkd_phrase = original_str
result = result.replace(original_str, linkd_phrase)
print(result)
return result
div.decompose()
I remove every existing <a> with class “katya_link” so that I can use this over and over again, e.g. if I change phrases’ links or some phrases and being removed and added and more/less phrases can get their linkssoup.findAll("u")
I will be adding links to whatever is found between<u>
‘s, so I will need this till the end.result
is made from the source html, but with<u>
removed and made in a single line. You can replace line separation with<br>
, if needed.just_text
andoriginal
are what I will look for and what I will add links toresult.replace(original_str, linkd_phrase)
so after I made a new contentlinkd_phrase
I replace the original I said we will need till the end
Don’t forget that you won’t modify html_source
like this:
html_source.replace('<u>', '')
Only this way:
html_source = html_source.replace('<u>', '')
Template
In order to not see plain html:
<h1>Phrases</h1>
<p>The world was on <i>fire</i> and no one could save me but you. (<a href="/phrases/13/link" class="katya_link">link</a>)</p>
<p>Something 2</p>
It's strange what <i>desire</i> will make foolish people do (<a href="/phrases/46/link" class="katya_link">link</a>)
But processed html:

You need to use |safe
inside the temple tag. Like this:
{{ html_text | safe }}
Template language in Django is pretty simplistic, what actually fits ‘every has its place’ ideology well. However, there are some built-in tag that would be entertaining to read especially to those who has a bit of experience of working with templates. Here is Django 2.2 built-in tags page, but you can choose a version in the right bottom corner.