PyQt: самый простой способ сделать CRUD UI для существующей базы данных?


В наименьшем количестве кода, как я должен перечислить (сотни) столбцов в существующей таблице базы данных и создать табличное представление, которое связано с базой данных с соответствующими типу виджетами в ячейках таблицы для изменения данных?

Я понимаю, что раньше это было очень просто, благодаря мастеру подключения к базе данных Qt Designer, но теперь он устарел.

1 4

1 ответ:

Самым простым способом, как было сказано, является использование QSqlTableModel. Предположим, что мы хотим:

  • просмотр данных и переключение между таблицами
  • редактирование данных с помощью соответствующих редакторов, например QSpinBox для целых чисел
  • вставить строки
  • и удалить строки

Хорошо, сначала нам нужно получить список всех таблиц в базе данных. Это может быть достигнуто с помощью метода QSqlDatabase::tables. Также я буду использовать QComboxBox, чтобы показать таблицы:

 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())

Теперь мы уже можем переключаться между таблицы базы данных и редактировать данные. Но редактор по умолчанию - QLineEdit. Мы можем предоставить другие редакторы, использующие класс QItemDelegate. В функции createEditor мы можем получить тип столбца из QSqlField. Есть недостаток, потому что по крайней мере для SQLite для DATETIME он всегда возвращает string (но это SQLite :)). Вероятно, вам следует найти другой способ получить этот тип.

 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)

Также в главном окне мы должны создать и подключить делегат с combobox для обновления имени таблицы:

Класс Главное Окно (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)

И последний шаг-реализация функций insert и delete:

 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)