Monthly Archives: November 2019

Python Flask custom view filter

For my current project I wanted to have a form with a search term which lists a table of results. I’m not mormally one for presentation but in this case I wanted to highlight the search term in the results table.

Sanitizing input data

Of course, this is an instance of taking form-submitted data and then displaying it on a different page.

This is something I’d normally try to avoid doing, but I thought I’d take the opportunity to apply some input validation and sanitization and get used to applying such ideas in general.

Python has an HTML parser library that helps to make this task straightforward.

Add a subclass of HTMLParser like

from html.parser import HTMLParser

class HTMLStripper(HTMLParser):
    def __init__(self):
        self.fed = []
    def handle_data(self, d):
    def handle_entityref(self, name):
        self.fed.append('&%s;' % name)
    def get_data(self):
        return ''.join(self.fed)

And apply the class using

def validate_text(str):
    s = HTMLStripper()
    return("", s.get_data())
(Apologies for the formatting; doing code in WordPress is very hit and miss)


Custom filter

I had hoped that the Jinja2 replace filter would do the trick but it is only case-senstive so would work when the search term was capitalized at the beginning of the retrieved text.

The only way to handle all cases regardless of case would be to write my own filter.

There are three steps:

  • writing a python function for the filter,
  • registering it in the jinja2 environment, and,
  • using it in a view template

Filter function

The filter function is a basic Python function that simply does a case insensitive search and replace of the word inside the text without changing the matching word but adding some highlighting HTML.

def highlight_text(text, word, cls):
    p = re.compile(word, re.IGNORECASE)
    m =
    if m:
        hstr = ("<span class='%s'>%s</span>" % (cls,
        return(p.sub(hstr, text))

The use of is important here and the function won’t work as expected if re.match() is used.

Filter register

The filter is registered with Jinja2 using the following

application.jinja_env.filters['highlight_text'] = highlight_text

Jinja2 template

The custom filter is used in the same way as any other filter

<td>{{ search.text|highlight_text(search_term, 'highlight-cue')|safe }}</td>

The search.text is the first argument passed to the filter function; the search_term and CSS class name are the others, in order.



The following were very helpful in developing the solution described on this page.