Фильтр для нескольких таблиц QSqlTableModel

Есть две таблицы category и equipment.
Пытаюсь сделать для них фильтр, но выходит, что в equipment он работает,
а в category нет... =(

Минимальный пример:

import re
import sys
from PyQt5 import QtSql
from PyQt5.Qt import *

class Example(QMainWindow):
    def __init__(self):
        super().__init__()

        self.createConnection()
        self.fillTable()  # !!!
        self.createModel()
        self.initUI()

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.table_box = QComboBox()
        self.table_box.addItems(["Оборудование", "Категории"])
        self.table_box.activated[str].connect(self.table_select)
        search_str = QLineEdit()
        search_str.setPlaceholderText("Введите строку поиска")
        search_str.textChanged.connect(self.update_filter)

        layout = QVBoxLayout(self.centralWidget)
        layout.addWidget(self.view)
        layout.addWidget(self.table_box)
        layout.addWidget(search_str)

    def createConnection(self):
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("test_1318914.db")  # !!! .db
        if not self.db.open():
            print("Cannot establish a database connection")
            return False

    def fillTable(self):
        self.db.transaction()
        q = QtSql.QSqlQuery()
        #                             vvvvvvvv
        q.exec_("DROP TABLE IF EXISTS category;")
        q.exec_("CREATE TABLE category (id INT PRIMARY KEY, catname TEXT);")
        q.exec_("INSERT INTO category VALUES (1, 'Расходники');")
        q.exec_("INSERT INTO category VALUES (2, 'Носители');")

        #                             vvvv
        q.exec_("DROP TABLE IF EXISTS equipment;")
        q.exec_("CREATE TABLE equipment (Name TEXT, Quantity INT, Category INT);")
        q.exec_("INSERT INTO equipment VALUES ('Барабан для принтера', 8, 1);")
        q.exec_("INSERT INTO equipment VALUES ('Бумага для принтера', 3, 1);")
        q.exec_("INSERT INTO equipment VALUES ('Дискета', 10, 2);")
        self.db.commit()

    def createModel(self):
        self.model = QtSql.QSqlRelationalTableModel()
        self.model.setTable("equipment")
        self.model.select()

    def initUI(self):
        self.view = QTableView()
        self.view.setModel(self.model)
        self.view.setColumnWidth(0, 150)
        mode = QAbstractItemView.SingleSelection
        self.view.setSelectionMode(mode)


    def update_filter(self, text):
        if self.table_box.currentText() == 'Категории':
            s = re.sub("[\W_]+", "", text)
            filter_str = 'FROM category WHERE catname LIKE "%{}%"'.format(s)
            self.model.setFilter(filter_str)
        elif self.table_box.currentText() == 'Оборудование':
            s = re.sub("[\W_]+", "", text)
            filter_str = 'Name LIKE "%{}%"'.format(s)
            self.model.setFilter(filter_str)

    def table_select(self, text):
        if text == 'Категории':
            self.model.setTable("category")
            self.model.select()
        elif text == 'Оборудование':
            self.model.setTable("equipment")
            self.model.select()

    def closeEvent(self, event):
        if (self.db.open()):
            self.db.close()



if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Example()
    w.setWindowTitle("Search")
    w.resize(430, 250)
    w.show()
    sys.exit(app.exec_())

Действия:

  1. Запускаю пример, появляется окно вида:

введите сюда описание изображения

  1. Ввожу в QLineEdit например "Ба", он выбирает нужное:

введите сюда описание изображения

  1. Переключаю на "Категории":

введите сюда описание изображения

  1. И вот при попытке поиска в таблице "Категории", он не ищет =(

введите сюда описание изображения


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

Автор решения: Konstantin

https://doc.qt.io/qtforpython/PySide6/QtSql/QSqlTableModel.html?highlight=setfilter#PySide6.QtSql.PySide6.QtSql.QSqlTableModel.setFilter

В общем, перемудрил немного, по документации: фильтр - это WHERE предложение SQL без ключевого слова WHERE. Проще говоря не надо городить SQL запрос целиком, просто обращаемся к полю текущей таблицы и всё.

Например, вместо:

filter_str = 'FROM category WHERE catname LIKE "%{}%"'.format(s)

Пишем:

filter_str = 'catname LIKE "%{}%"'.format(s)
→ Ссылка
Автор решения: S. Nick

Как вариант:

import re
import sys
from PyQt5 import QtSql
from PyQt5.Qt import *


class Example(QMainWindow):
    def __init__(self):
        super().__init__()

        self.createConnection()
        self.fillTable()  # !!!
        self.createModel()
        self.initUI()
        
# +++ vvvv       
        self.model_category  = self.model.relationModel(2)   # QtSql.QSqlTableModel
        #print(f'm_cat tableName == {self.model_category.tableName()}')
        #print(f'm_cat rowCount  == {self.model_category.rowCount()}')
        self.model_category.setHeaderData(0, Qt.Horizontal, "ID")
        self.model_category.setHeaderData(1, Qt.Horizontal, "Категория")
# +++ ^^^^

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.table_box = QComboBox()
        self.table_box.addItems(["Оборудование", "Категории"])
        self.table_box.activated[str].connect(self.table_select)
        self.search_str = QLineEdit()                               # +++ self.
        self.search_str.setPlaceholderText("Введите строку поиска")
        self.search_str.textChanged.connect(self.update_filter)

        layout = QVBoxLayout(self.centralWidget)
        layout.addWidget(self.view)
        layout.addWidget(self.table_box)
        layout.addWidget(self.search_str)

    def createConnection(self):
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("test_1318914.db")  # !!! .db
        if not self.db.open():
            print("Cannot establish a database connection")
            return False

    def fillTable(self):
        self.db.transaction()
        q = QtSql.QSqlQuery()
        
        q.exec_("DROP TABLE IF EXISTS category;")
        q.exec_("CREATE TABLE category (id INT PRIMARY KEY, catname TEXT);")
        q.exec_("INSERT INTO category VALUES (1, 'Расходники');")
        q.exec_("INSERT INTO category VALUES (2, 'Носители');")

        q.exec_("DROP TABLE IF EXISTS equipment;")
        q.exec_("CREATE TABLE equipment (Name TEXT, Quantity INT, Category INT);")
        q.exec_("INSERT INTO equipment VALUES ('Барабан для принтера', 8, 1);")
        q.exec_("INSERT INTO equipment VALUES ('Бумага для принтера', 3, 1);")
        q.exec_("INSERT INTO equipment VALUES ('Дискета', 10, 2);")
        self.db.commit()

    def createModel(self):
        self.model = QtSql.QSqlRelationalTableModel()
        self.model.setTable("equipment")
# +++ vvvv
        self.model.setHeaderData(0, Qt.Horizontal, "Название")
        self.model.setHeaderData(1, Qt.Horizontal, "Кол-во")
        self.model.setHeaderData(2, Qt.Horizontal, "Категория")
        self.set_relation()
# +++ ^^^^       
        self.model.select()
        
# +++ vvvv
    def set_relation(self):
        self.model.setRelation(2, QtSql.QSqlRelation(
            "category",
            "id",
            "catname"
        ))        
# +++ ^^^^

    def initUI(self):
        self.view = QTableView()
        self.view.setModel(self.model)
        self.view.setColumnWidth(0, 150)
        mode = QAbstractItemView.SingleSelection
        self.view.setSelectionMode(mode)

    def update_filter(self, text):
        if self.table_box.currentText() == 'Категории':
            s = re.sub("[\W_]+", "", text)
#            filter_str = 'FROM category WHERE catname LIKE "%{}%"'.format(s)
            filter_str = 'catname LIKE "%{}%"'.format(s)
            self.model_category.setFilter(filter_str)                  # +++
        elif self.table_box.currentText() == 'Оборудование':
            s = re.sub("[\W_]+", "", text)
            filter_str = 'Name LIKE "%{}%"'.format(s)
            self.model.setFilter(filter_str)

    def table_select(self, text):
        self.search_str.clear()                        # +++
        if text == 'Категории':
#            self.model.setTable("category")
#            self.model.select()
            self.view.setModel(self.model_category)     # +++   
        elif text == 'Оборудование':
#            self.model.setTable("equipment")
#            self.model.select()
            self.view.setModel(self.model)              # +++

    def closeEvent(self, event):
        if (self.db.open()):
            self.db.close()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Example()
    w.setWindowTitle("Search")
    w.resize(430, 250)
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения

введите сюда описание изображения

→ Ссылка