In the least amount of code, how should I enumerate the (hundreds) of columns in an existing database table and create a table view that is coupled to the database with type-appropriate widgets in the table cells to modify the data?
I understand this used to be dead simple, thanks to Qt Designer's Database Connection Wizard, but it's been deprecated.
The simplest way as it was said is using QSqlTableModel.
Let's assume that we want to:
Ok, first we need to get the list of all the tables in the database. This can be achieved using QSqlDatabase::tables method. Also I will use QComboxBox to show tables:
class MainWindow(QtWidgets.QFrame):
def __init__(self, parent=None):
QtWidgets.QFrame.__init__(self, parent)
# Connect to database
self.__database__ = QtSql.QSqlDatabase.addDatabase('QSQLITE')
self.__database__.setDatabaseName('sqlite.db')
self.__database__.open()
# Create QComboBox to show tables
self.__tableNames__ = QtWidgets.QComboBox(self)
# Create QTableView to show table's data
self.__tableGrid__ = QtWidgets.QTableView(self)
# Create table model
self.__tableModel__ = QtSql.QSqlTableModel(self, self.__database__)
self.__tableGrid__.setModel(self.__tableModel__)
# Connect combobox signal to update model
self.__tableNames__.currentIndexChanged[str].connect(self.__tableModel__.setTable)
self.__tableNames__.currentIndexChanged[str].connect(self.__tableModel__.select)
# Set the list of the tables to combobox
self.__tableNames__.addItems(self.__database__.tables())
Now we already can switch between database's tables and edit the data. But the default editor is QLineEdit. We can provide others editors using QItemDelegate class. In createEditor function we can get the type of column from QSqlField. There is a shortcoming because at least for SQLite for the DATETIME it always returns string (but it is SQLite :)). Probably you should find other way to get the type.
class SqlItemDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, database, parent=None):
QtWidgets.QStyledItemDelegate.__init__(self, parent)
self.__table__ = ''
self.__database__ = database
def setTable(self, table):
self.__table__ = table
def createEditor(self, parent, option, index):
record = self.__database__.record(self.__table__)
column_type = record.field(record.fieldName(index.column())).type()
print(record.fieldName(index.column()), column_type)
if column_type == QtCore.QVariant.Double:
return QtWidgets.QDoubleSpinBox(parent)
if column_type == QtCore.QVariant.DateTime:
return QtWidgets.QDateTimeEditor(parent)
# etc.
return QtWidgets.QStyledItemDelegate.createEditor(self, parent, option, index)
Also in the MainWindow we should create and connect the delegate with combobox to update table name:
class MainWindow(QtWidgets.QFrame): def init(self, parent=None): # .....
self.__delegate__ = SqlItemDelegate(self.__database__, self)
self.__tableGrid__.setItemDelegate(self.__delegate__)
self.__tableNames__.currentIndexChanged[str].connect(self.__delegate__.setTable)
And the last step is implementation of insert and delete functions:
class MainWindow(QtWidgets.QFrame):
def __init__(self, parent=None):
# .....
self.__insertRow__ = QtWidgets.QPushButton('Insert', self)
self.__insertRow__.clicked.connect(self.insertRow)
self.__deleteRow__ = QtWidgets.QPushButton('Delete', self)
self.__deleteRow__.clicked.connect(self.deleteRow)
def deleteRow(self):
index = self.__tableGrid__.currentIndex()
self.__tableModel__.removeRows(index.row(), 1)
def insertRow(self):
self.__tableModel__.insertRows(0, 1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With