Search code examples
pythonflaskflashmarkup

How do I markup a flash message in Flask?


I was running a Flask application using Python 3.9.13, Flask 1.1.2, Jinja2 2.11.3, and MarkupSafe 1.1.1, using a Redis (3.5.3) as my session store. When I created a flash message with

flash(Markup('<b>This</b> is a <b>WARNING</b>.'),category="warning")

Flask would display (as expected)

This is a WARNING.

with the selected backbrouund color associated with the warning flash messages.

I'm trying to move the application to Python 3.12.4, Flask 3.0.3, and MarkupSafe 2.1.5 (Jinja2 ia at 3.1.4, but Flask moved to use MarkupSafe directly, instead of importing it from Jinja2, so I don't think that's relevant, Redis is 5.0.8). However, when I try to redirect to a page with that set as the flash message, the app fails sliently with an Internal Server Error.

Digging deeply into Flask, I can see that it's throwing an exception Encoding objects of type Markup is unsupported, when it's handling the process_response and trying to save the session https://github.com/pallets/flask/blob/main/src/flask/app.py#L1301, and it seems to be caused by the Markup object in the _flashes list. If convert the Markup to a string, it doesn't fail, but the message is displayed as:

<b>This</b> is a <b>WARNING</b>. (It does display with the correct background color.)

Is there a way to format a flash message in the current Flask like we used to be able to do in earlier versions, or am I doing something wrong?


Solution

  • So the suggestion by @Detlef works. I had to do three things:

    (1) call flash with a plain string:

    flash('<b>This</b> is a <b>WARNING</b>.',category="warning")
    

    (2) change the jinja template from:

      <div class="container-fluid">
      {%- with messages = get_flashed_messages(with_categories=True) %}
      {%- if messages %}
        <div class="row">
          <div class="col-md-13">
            {{utils.flashed_messages(messages)}}
          </div>
        </div>
      {%- endif %}
      {%- endwith %}
      </div>
    

    to

       {%- with messages = get_flashed_messages(with_categories=True) %}
       {%- if messages %}
          {% for category, message in messages %}
          <div class="container-fluid flashed-messages" style="margin-top:1em;padding-left:5em;padding-right:5em">
             <div class="row">
                <div class="col-md-13">
                   <div class="{{ category }}">{{ message | safe }}</div>
                </div>
             </div>
          </div>
          {% endfor %}
       {%- endif %}
       {%- endwith %}
    

    and

    (3) make sure my static/css/app.css had the appropriate classes used by the code (which only uses error, message, warning, and success):

    .error {
      color: white;
      background-color: red
    }
    
    .message {
      color: black;
      background-color: lightblue
    }
    
    .warning {
      color: black;
      background-color: orange
    }
    
    .success {
      color: white;
      background-color: green
    }
    

    This gave me formatted flash messages with the correct background colors. Thank you, @Detlef!