Как при переключении таблицы из базы менять столбцы, которые не редактируются?

Есть код:

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

class ReadOnlyDelegate(QStyledItemDelegate):
    def createEditor(self, parent, option, insex):
        return   


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)

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

    def createConnection(self):
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("test_1318914.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, description 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")
        self.model.select()

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

        self.delegate = ReadOnlyDelegate(self.view)               
        self.view.setItemDelegateForColumn(2, self.delegate)      
        
        mode = QAbstractItemView.SingleSelection
        self.view.setSelectionMode(mode)

    def table_select(self, text):
        if text == 'Категории':
            self.model.setTable("category")
            self.view.setItemDelegateForColumn(0, self.delegate)     
            self.model.select()
        elif text == 'Оборудование':
            self.model.setTable("equipment")
            self.view.setItemDelegateForColumn(2, self.delegate)     
            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("No edit")
    w.resize(430, 250)
    w.show()
    sys.exit(app.exec())

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

Что получается. Запускается табличка "Оборудование", у которой не редактируемый столбец "Category" (индекс 2),
потом переключаемся на табличку "Категории", у которой не редактируемый столбец должен быть только "id",
а сейчас столбец "description" тоже не редактируемый (оставшийся делегат от предыдущей таблицы).

Мне нужно при переключении таблицы из базы данных менять те столбцы, на которые будет распространяться делегат "не редактирования" в представлении таблицы.
Как это сделать?


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

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

Вот так просто =) Если вместо делегата в setItemDelegateForColumn подставить None, то меняя представления из таблиц базы данных можно изменять какие столбцы будут редактируемыми, а какие нет.

self.table.setItemDelegateForColumn(2, None)

Воспроизводимый пример (изменения отмечены # <---):

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

class ReadOnlyDelegate(QStyledItemDelegate):
    def createEditor(self, parent, option, insex):
        return   


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)

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

    def createConnection(self):
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("test_1318914.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, description 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")
        self.model.select()

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

        self.delegate = ReadOnlyDelegate(self.view)               
        self.view.setItemDelegateForColumn(2, self.delegate)      
        
        mode = QAbstractItemView.SingleSelection
        self.view.setSelectionMode(mode)

    def table_select(self, text):
        if text == 'Категории':
            self.model.setTable("category")
            self.view.setItemDelegateForColumn(0, self.delegate)
            self.view.setItemDelegateForColumn(2, None)          # <- +++
            self.model.select()
        elif text == 'Оборудование':
            self.model.setTable("equipment")
            self.view.setItemDelegateForColumn(0, None)          # <- +++
            self.view.setItemDelegateForColumn(2, self.delegate)     
            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("No edit")
    w.resize(430, 250)
    w.show()
    sys.exit(app.exec())
→ Ссылка
Автор решения: Konstantin

Еще один вариант, через flags, т.е. создать свой класс наследованный от QSqlRelationalTableModel с переопределением метода flags и созданием своего атрибута self.ro_cols (типа read-only columns).

Воспроизводимый пример (изменения отмечены # <---):

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

class My_SqlTableModel(QSqlRelationalTableModel):                            # <---
    def __init__(self):                                                      # <---      
        super().__init__()                                                   # <---
        self.ro_cols = []# read-only columns                                 # <---
        
    def flags(self,index):                                                   # <---
        col = index.column()                                                 # <---
        if col in self.ro_cols:                                              # <---
            return Qt.NoItemFlags                                            # <---
        return Qt.ItemIsEnabled | Qt.ItemIsEditable | Qt.ItemIsSelectable    # <---
 

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)
 
        layout = QVBoxLayout(self.centralWidget)
        layout.addWidget(self.view)
        layout.addWidget(self.table_box)
 
    def createConnection(self):
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("test_1318914.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, description 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 = My_SqlTableModel()
        self.model.setTable("equipment")
        self.model.ro_cols =[2]                       # <---
        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 table_select(self, text):
        if text == 'Категории':
            self.model.setTable("category")
            self.model.ro_cols =[0]                    # <---
            self.model.select()
        elif text == 'Оборудование':
            self.model.setTable("equipment")
            self.model.ro_cols =[2]                    # <---    
            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("No edit")
    w.resize(430, 250)
    w.show()
    sys.exit(app.exec())
→ Ссылка