Как разметить flash-сообщение в Flask?

Вопрос или проблема

Я запускал приложение Flask, используя Python 3.9.13, Flask 1.1.2, Jinja2 2.11.3 и MarkupSafe 1.1.1, используя Redis (3.5.3) в качестве хранилища сессий. Когда я создавал всплывающее сообщение с помощью

flash(Markup('<b>Это</b> <b>ПРЕДУПРЕЖДЕНИЕ</b>.'),category="warning")

Flask отображал (как и ожидалось)

Это <b>ПРЕДУПРЕЖДЕНИЕ</b>.

с выбранным фоновым цветом, связанным с предупреждающими всплывающими сообщениями.

Я пытаюсь перенести приложение на Python 3.12.4, Flask 3.0.3 и MarkupSafe 2.1.5 (Jinja2 на 3.1.4, но Flask начал использовать MarkupSafe непосредственно, вместо импорта его из Jinja2, так что не думаю, что это имеет значение, Redis на 5.0.8). Однако, когда я пытаюсь перенаправить на страницу с этим установленным как всплывающее сообщение, приложение завершает работу тихо с ошибкой внутреннего сервера.

Глубже изучив Flask, я вижу, что возникает исключение Encoding objects of type Markup is unsupported, когда он обрабатывает process_response и пытается сохранить сессию https://github.com/pallets/flask/blob/main/src/flask/app.py#L1301, и, похоже, это связано с объектом Markup в списке _flashes. Если я преобразую Markup в строку, это не приводит к сбою, но сообщение отображается как:

<b>Это</b> <b>ПРЕДУПРЕЖДЕНИЕ</b>. (Хотя оно отображается с правильным фоновым цветом.)

Есть ли способ отформатировать всплывающее сообщение в текущем Flask так, как мы могли это делать в предыдущих версиях, или я что-то делаю не так?

Ответ или решение

Ваша ситуация с использованием flash-сообщений в Flask очень распространена, особенно после обновления до более новых версий. Рассмотрим, как корректно отображать flash-сообщения с использованием HTML-разметки, чтобы избежать ошибок, связанных с бинарным кодированием, которые возникли в более новых версиях Flask и MarkupSafe.

Проблема

Как вы уже заметили, при использовании Markup для создания flash-сообщений возникает ошибка Encoding objects of type Markup is unsupported. Это связано с тем, что Flask теперь не может сохранить объекты типа Markup в сессии, так как они не поддерживают сериализацию.

Решение

Для решения этой проблемы можно воспользоваться следующими подходами:

  1. Используйте обычные строки: Вместо того чтобы сохранять Markup, просто сохраните строку и используйте | safe в шаблоне. Это позволят вам избежать проблем с сериализацией.

    Чтобы сделать это, следует изменить ваш код следующим образом:

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

    Затем, в вашем шаблоне используйте | safe для отображения содержимого flash-сообщения:

    {% with messages = get_flashed_messages(with_categories=True) %}
        {% if messages %}
            {% for category, message in messages %}
                <div class="alert alert-{{ category }}">
                    {{ message|safe }}
                </div>
            {% endfor %}
        {% endif %}
    {% endwith %}
  2. Создайте свой класс Flash-сообщения: Если вам нужно использовать Markup, вы можете создать простую обертку, чтобы сериализовать и десериализовать Markup в строке.

    Вот пример:

    from flask import flash, session
    from markupsafe import Markup
    
    class FlashMessage:
        def __init__(self, message, category):
            self.message = message
            self.category = category
    
        def __str__(self):
            return str(self.message)
    
    def flash_markup(message, category="message"):
        flash(FlashMessage(Markup(message), category))
    
    # Используйте flash_markup для добавления flash-сообщений
    flash_markup('<b>This</b> is a <b>WARNING</b>.', category="warning")

    В шаблоне вы сможете обработать его аналогично первому методу (не забыв использовать | safe).

Итог

Таким образом, для корректного отображения flash-сообщений с HTML-разметкой в текущих версиях Flask, вы должны использовать строки и предоставлять Flask возможность обрабатывать их с помощью | safe в шаблонах. Это избавит вас от проблем с сериализацией и обеспечит правильное отображение flash-сообщений.

Оцените материал
Добавить комментарий

Капча загружается...