Запись html в Sqllite3 из под PyQt5

При попытке записать в бд html из QTextBrowser.toHtml() происходит ошибка sqlite3.OperationalError.

В интернете нарыл только метод с использованием QString, но в PyQt5 его нет. Ссылка.

Минимально воспроизводимый пример:

import sqlite3

from PyQt5 import QtWidgets
import sys

from PyQt5.QtGui import QTextCharFormat, QFont

conn = sqlite3.connect("testdb.db")
cursor = conn.cursor()
cursor.execute("""CREATE TABLE IF NOT EXISTS texts
                  (content TEXT)
               """)
conn.commit()


class Window(QtWidgets.QWidget):

    def __init__(self):
        super(Window, self).__init__()

        box = QtWidgets.QVBoxLayout()
        self.textbrowser = QtWidgets.QTextBrowser()
        self.textbrowser.setFixedSize(300, 300)
        self.textbrowser.setReadOnly(False)

        self.make_bold_button = QtWidgets.QPushButton('set bold')
        self.make_bold_button.clicked.connect(self.set_bold_foo)

        self.save_button = QtWidgets.QPushButton('save')
        self.save_button.clicked.connect(self.save_text_foo)
        box.addWidget(self.textbrowser)
        box.addWidget(self.make_bold_button)
        box.addWidget(self.save_button)

        self.setLayout(box)

    def set_bold_foo(self):
        cursor = self.textbrowser.textCursor()
        text_char_format = QTextCharFormat()
        text_char_format.setFontWeight(QFont.Bold)
        cursor.mergeCharFormat(text_char_format)

    def save_text_foo(self):
        cursor.execute(f"""INSERT INTO texts
                      VALUES ('{self.textbrowser.toHtml()}')"""
                       )
        conn.commit()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = Window()
    w.show()
    app.exec_()

Ответы (2 шт):

Автор решения: Sergey Tatarincev

А вы не думали что будет когда в html встретится символ закрывающей кавычки?

У вас прямо классический пример для демонстрации атак с использованием sql инъекции.

Используйте QSqlQuery с передачей параметров через bindValue. В этом случае sql драйвер сам позаботится https://doc.qt.io/qtforpython/overviews/sql-sqlstatements.html

В вашем случае соответственно

from PyQt5.QtSql import QSqlDatabase, QSqlQuery

...
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('testdb.db')
db.open()

...

query = QSqlQuery()
query.prepare("INSERT INTO texts VALUES (:content)")
query.bindValue(":content", self.textbrowser.toHtml())
query.exec()
→ Ссылка
Автор решения: gil9red

Дополнение к соседнему ответу, для sqlite3 из python binding-параметры передавайте через ?:

cursor.execute("INSERT INTO texts VALUES (?)", [self.textbrowser.toHtml()])
conn.commit()
→ Ссылка