【问题标题】:How filter SQLite3 table in PyQt5PyQt5中如何过滤SQLite3表
【发布时间】:2021-05-18 14:47:55
【问题描述】:

我正在尝试创建一个搜索栏来过滤表中的数据,但看起来模型没有链接到行编辑表有效,但我无法使用它过滤数据库数据(它适用于列表)怎么了?

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        mainLayout = QVBoxLayout()
        conn = sqlite3.connect("banco_cadastro.db.db")
        cursor = conn.cursor()
        list = (cursor.fetchall())
        model = QStandardItemModel(len(list), 5)
        model.setHorizontalHeaderLabels(['Clients'])
        for row, company in enumerate(list):
            item = QStandardItem(company)
            model.setItem(row, 0, item)
        filter_proxy_model = QSortFilterProxyModel()
        filter_proxy_model.setSourceModel(model)
        filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        filter_proxy_model.setFilterKeyColumn(0)
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(779, 693)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.textChanged.connect(filter_proxy_model.setFilterRegExp)
        mainLayout.addWidget(self.lineEdit)
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setObjectName("tableWidget")
        MainWindow.setCentralWidget(self.centralwidget)
        connection = sqlite3.connect('banco_cadastro.db')
        query = "SELECT * FROM cadastro"
        result = connection.execute(query)
        list = (cursor.fetchall())

        for row_number, row_data in enumerate(result):
            self.tableWidget.insertRow(row_number)

            for column_number, data in enumerate(row_data):
                self.tableWidget.setItem(row_number, column_number, QtWidgets.QTableWidgetItem(str(data)))

        connection.close()

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python sqlite pyqt5 qtableview


    【解决方案1】:

    免责声明:在这篇文章中,我将只关注背景目标,而不是 OP 的错误(例如将 QStandardItemModel 与 QTableWidget 组合,或者尝试使用未连接到的 QSortFilterProxyModel任何东西)。

    我将借此机会展示如何使用 PyQt5(它也适用于 PySide2)过滤 sqlite 表的不同方法(相同的概念可以应用于其他 DB)。

    - QTableWidget + sqlite3 模块

    一种可能的解决方案是遍历行并验证它是否满足所需条件,如果满足则该行将可见,否则该行将被隐藏。

    import sqlite3
    
    from PyQt5 import QtCore, QtWidgets
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableWidget()
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.connection = sqlite3.connect("database.db")
    
            self.populate_table("SELECT * FROM foo_table")
            self.edit.textChanged.connect(self.filter_table)
    
        def populate_table(self, query, values=None):
            cursor = self.connection.cursor()
            if values is None:
                cursor.execute(query)
            else:
                cursor.execute(query, values)
    
            name_of_columns = [e[0] for e in cursor.description]
            self.table.setColumnCount(len(name_of_columns))
            self.table.setRowCount(0)
            self.table.setHorizontalHeaderLabels(name_of_columns)
            self.combo.clear()
            self.combo.addItems(name_of_columns)
    
            for i, row_data in enumerate(cursor.fetchall()):
                self.table.insertRow(self.table.rowCount())
                for j, value in enumerate(row_data):
                    item = QtWidgets.QTableWidgetItem()
                    item.setData(QtCore.Qt.DisplayRole, value)
                    self.table.setItem(i, j, item)
    
        def filter_table(self, text):
            if text:
                filter_column = self.combo.currentIndex()
    
                for i in range(self.table.rowCount()):
                    item = self.table.item(i, filter_column)
                    if self.filter_row(item, text):
                        self.table.showRow(i)
                    else:
                        self.table.hideRow(i)
            else:
                for i in range(self.table.rowCount()):
                    self.table.showRow(i)
    
        def filter_row(self, item, text):
            return text in item.text()
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    另一种可能的解决方案是删除所有数据并使用过滤器发出新请求。

    import sqlite3
    
    from PyQt5 import QtCore, QtWidgets
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableWidget()
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.connection = sqlite3.connect("database.db")
    
            self.populate_table("SELECT * FROM foo_table")
            self.edit.textChanged.connect(self.filter_table)
    
        def populate_table(self, query, values=None):
            cursor = self.connection.cursor()
            if values is None:
                cursor.execute(query)
            else:
                cursor.execute(query, values)
    
            name_of_columns = [e[0] for e in cursor.description]
            self.table.setColumnCount(len(name_of_columns))
            self.table.setRowCount(0)
            self.table.setHorizontalHeaderLabels(name_of_columns)
            self.combo.clear()
            self.combo.addItems(name_of_columns)
    
            for i, row_data in enumerate(cursor.fetchall()):
                self.table.insertRow(self.table.rowCount())
                for j, value in enumerate(row_data):
                    item = QtWidgets.QTableWidgetItem()
                    item.setData(QtCore.Qt.DisplayRole, value)
                    self.table.setItem(i, j, item)
    
        def filter_table(self, text):
            if text:
                self.populate_table(
                    "SELECT * FROM foo_table WHERE {} LIKE ?".format(
                        self.combo.currentText()
                    ),
                    ["%{}%".format(text)],
                )
            else:
                self.populate_table("SELECT * FROM foo_table")
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    - QTableView + QStandardItemModel + sqlite3 模块

    同上逻辑:

    import sqlite3
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableView()
            self.model = QtGui.QStandardItemModel()
            self.table.setModel(self.model)
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.connection = sqlite3.connect("database.db")
    
            self.populate_table("SELECT * FROM foo_table")
            self.edit.textChanged.connect(self.filter_table)
    
        def populate_table(self, query):
            cursor = self.connection.cursor()
            cursor.execute(query)
    
            name_of_columns = [e[0] for e in cursor.description]
            self.model.setColumnCount(len(name_of_columns))
            self.model.setRowCount(0)
            self.model.setHorizontalHeaderLabels(name_of_columns)
            self.combo.clear()
            self.combo.addItems(name_of_columns)
    
            for i, row_data in enumerate(cursor.fetchall()):
                self.model.insertRow(self.model.rowCount())
                for j, value in enumerate(row_data):
                    item = QtGui.QStandardItem()
                    item.setData(value, QtCore.Qt.DisplayRole)
                    self.model.setItem(i, j, item)
    
        def filter_table(self, text):
            if text:
                filter_column = self.combo.currentIndex()
    
                for i in range(self.model.rowCount()):
                    item = self.model.item(i, filter_column)
                    if self.filter_row(item, text):
                        self.table.showRow(i)
                    else:
                        self.table.hideRow(i)
            else:
                for i in range(self.model.rowCount()):
                    self.table.showRow(i)
    
        def filter_row(self, item, text):
            return text in item.text()
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    
    import sqlite3
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableView()
            self.model = QtGui.QStandardItemModel()
            self.table.setModel(self.model)
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.connection = sqlite3.connect("database.db")
    
            self.populate_table("SELECT * FROM foo_table")
            self.edit.textChanged.connect(self.filter_table)
    
        def populate_table(self, query, values=None):
            cursor = self.connection.cursor()
            if values is None:
                cursor.execute(query)
            else:
                cursor.execute(query, values)
    
            name_of_columns = [e[0] for e in cursor.description]
            self.model.setColumnCount(len(name_of_columns))
            self.model.setRowCount(0)
            self.model.setHorizontalHeaderLabels(name_of_columns)
            self.combo.clear()
            self.combo.addItems(name_of_columns)
    
            for i, row_data in enumerate(cursor.fetchall()):
                self.model.insertRow(self.model.rowCount())
                for j, value in enumerate(row_data):
                    item = QtGui.QStandardItem()
                    item.setData(value, QtCore.Qt.DisplayRole)
                    self.model.setItem(i, j, item)
    
        def filter_table(self, text):
            if text:
                self.populate_table(
                    "SELECT * FROM foo_table WHERE {} LIKE ?".format(
                        self.combo.currentText()
                    ),
                    ["%{}%".format(text)],
                )
            else:
                self.populate_table("SELECT * FROM foo_table")
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    还有使用 QSortFilterProxyModel 的选项:

    import sqlite3
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableView()
            self.model = QtGui.QStandardItemModel()
    
            self.proxy = QtCore.QSortFilterProxyModel()
            self.proxy.setSourceModel(self.model)
            self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
            self.table.setModel(self.proxy)
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.connection = sqlite3.connect("database.db")
    
            self.populate_table("SELECT * FROM foo_table")
            self.combo.currentIndexChanged.connect(self.proxy.setFilterKeyColumn)
            self.edit.textChanged.connect(self.proxy.setFilterRegExp)
    
        def populate_table(self, query, values=None):
            cursor = self.connection.cursor()
            if values is None:
                cursor.execute(query)
            else:
                cursor.execute(query, values)
    
            name_of_columns = [e[0] for e in cursor.description]
            self.model.setColumnCount(len(name_of_columns))
            self.model.setRowCount(0)
            self.model.setHorizontalHeaderLabels(name_of_columns)
            self.combo.clear()
            self.combo.addItems(name_of_columns)
    
            for i, row_data in enumerate(cursor.fetchall()):
                self.model.insertRow(self.model.rowCount())
                for j, value in enumerate(row_data):
                    item = QtGui.QStandardItem()
                    item.setData(value, QtCore.Qt.DisplayRole)
                    self.model.setItem(i, j, item)
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    - QTableView + QSqlQueryModel

    在这种情况下,最好的选择是使用 sql 更改查询来进行过滤:

    from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableView()
            self.model = QtSql.QSqlQueryModel()
            self.table.setModel(self.model)
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.populate_table("SELECT * FROM foo_table")
            self.edit.textChanged.connect(self.filter_table)
    
        def populate_table(self, query, values=None):
            q = QtSql.QSqlQuery(query)
            if values is not None:
                for value in values:
                    q.addBindValue(value)
                    print(value)
            if not q.exec_():
                print(q.lastError().text())
            self.model.setQuery(q)
            self.combo.clear()
            for i in range(self.model.columnCount()):
                self.combo.addItem(self.model.headerData(i, QtCore.Qt.Horizontal))
    
        def filter_table(self, text):
            if text:
                self.populate_table(
                    "SELECT * FROM foo_table WHERE {} LIKE ?".format(
                        self.combo.currentText()
                    ),
                    ["%{}%".format(text)],
                )
            else:
                self.populate_table("SELECT * FROM foo_table")
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName("database.db")
        if not db.open():
            sys.exit(-1)
    
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    另一种选择是应用隐藏行的技术或使用 QSortFilterProxyModel。

    - QTableView + QSqlTableModel

    在这种情况下应该使用 setFilter 方法:

    from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.edit = QtWidgets.QLineEdit()
            self.combo = QtWidgets.QComboBox()
            self.table = QtWidgets.QTableView()
            self.model = QtSql.QSqlTableModel()
            self.table.setModel(self.model)
    
            grid = QtWidgets.QGridLayout(self)
            grid.addWidget(self.edit, 0, 0)
            grid.addWidget(self.combo, 0, 1)
            grid.addWidget(self.table, 1, 0, 1, 2)
    
            self.model.setTable("foo_table")
            self.model.select()
    
            self.combo.clear()
            for i in range(self.model.columnCount()):
                self.combo.addItem(self.model.headerData(i, QtCore.Qt.Horizontal))
    
            self.edit.textChanged.connect(self.filter_table)
    
        def filter_table(self, text):
            f = " {} LIKE '%{}%'".format(self.combo.currentText(), text) if text else text
            self.model.setFilter(f)
            self.model.select()
    
    
    def main():
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName("database.db")
        if not db.open():
            sys.exit(-1)
    
        ex = Widget()
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    另一种选择是应用隐藏行的技术或使用 QSortFilterProxyModel。

    【讨论】:

    • 感谢您的精彩解释。
    猜你喜欢
    • 2015-07-13
    • 2020-08-01
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    相关资源
    最近更新 更多