PyQt5—操作数据库

操作数据库

一、关于数据库和数据库引擎

1、SQLite

  • 我在这里采用的数据库和数据库引擎是 SQLite,这是一个轻量级的数据库,麻雀虽小五脏俱全,具有自给自足、零配置、无服务器、事务性的 SQL 数据库引擎,同时相比 SQL Server 和 MySQL 具有更高的可移植性,只需将 .db 文件移植到装有 SQLite 的电脑就可以照样使用数据库了,适合作为应用配套的数据库。
  • SQLite 能够识别并执行通用的标准查询语言——SQL 语言

2、SQLite Studio

  • 如果不习惯命令窗口查看数据库的数据,想要像 SQL Server 或 MySQL 那样以可视化的表格视图查看数据,可以去 SQLitestudio 的官网下载便携版的 SQLitestudio。

3、简单示例

  • 建立一个 Python 脚本,代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/10/01 上午 10:07 
    # Author : 御承扬
    # e-mail:2923616405@qq.com
    # project:  PyQt5
    # File : dbOption01.py 
    # @software: PyCharm
    
    
    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtSql import *
    
    
    def createDB():
        db = QSqlDatabase.addDatabase('QSQLITE')
        db.setDatabaseName('./db/database.db')
    
        if not db.open():
            QMessageBox.critical(None, ("无法打开数据库连接"), ("无法建立到数据库的连接,这个例子需要SQLite支持"), QMessageBox.Cancel)
            return False
    
        query = QSqlQuery()
        query.exec_("create table people(id int primary key, name varchar(20), address varchar(30))")
        query.exec_("insert into people values(1, 'zhangsan', 'beijing')")
        query.exec_("insert into people values(2, 'wangwu', 'shanghai')")
        query.exec_("insert into people values(3, 'lisi', 'guangzhou')")
        query.exec_("insert into people values(4, 'zhaoliu', 'kunming')")
        db.close()
        return True
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        createDB()
        sys.exit(app.exec_())
    
  • 运行后会在脚本的同级目录的 db 文件夹下新建一个名为“database.db”的文件,使用 SQLiteStudio 打开数据库,查看里面的数据,如下图:
    在这里插入图片描述
    在这里插入图片描述

二、操作数据库

1、数据库模型视图

1.1、单页查询模型
  • PyQt5 提供了一个高级接口:QSqlTableModel,使得程序能够以可编辑的列表视图形式打开数据库中的数据表。
  • QSqlTableModel 类是一个可以读写的表格模型,当连接到数据库后,使用 setTable() 函数设置要查询的表,使用 setFilter() 函数设置过滤器条件(SQL 中 where 语句的条件一样),使用 select() 函数执行查询,使用 setEditStrategy() 函数设置“编辑策略”,编辑策略的可取值如下:
    编辑策略描述
    QSqlTableModel.OnFieldChange所有变更实时更新到数据库中
    QSqlTableModel.OnRowChange当用户选择不同的行时,在当前行进行变更
    QSqlTableModel.OnManualSubmit手动变更,不自动变更
  • 示例代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/10/01 下午 2:37 
    # Author : 御承扬
    # e-mail:2923616405@qq.com
    # project:  PyQt5
    # File : dbOption02.py 
    # @software: PyCharm
    
    
    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtSql import *
    
    
    def initializeModel(model):
        model.setTable('people')
        model.setEditStrategy(QSqlTableModel.OnFieldChange)
        model.select()
        model.setHeaderData(0, Qt.Horizontal, "ID")
        model.setHeaderData(1, Qt.Horizontal, "Name")
        model.setHeaderData(2, Qt.Horizontal, "address")
    
    
    def createView(title, model):
        view = QTableView()
        view.setModel(model)
        view.setWindowTitle(title)
        return view
    
    
    def addRow():
        ret = model.insertRows(model.rowCount(), 1)
        print('insertRows=%s' % str(ret))
    
    
    def findRow(i):
        delRow = i.row()
        print('del row=%s' % str(delRow))
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        db = QSqlDatabase.addDatabase('QSQLITE')
        db.setDatabaseName('./db/database.db')
        model = QSqlTableModel()
        delRow = -1
        initializeModel(model)
        view1 = createView("Table Model(View 1)", model)
        view1.clicked.connect(findRow)
    
        dlg = QDialog()
        layout = QVBoxLayout()
        layout.addWidget(view1)
        addBtn = QPushButton('添加一行')
        addBtn.clicked.connect(addRow)
        layout.addWidget(addBtn)
        delBtn = QPushButton('删除一行')
        delBtn.clicked.connect(lambda:
                               model.removeRow(view1.currentIndex().row()))
        layout.addWidget(delBtn)
        dlg.setLayout(layout)
        dlg.setWindowTitle('Database Demo')
        dlg.setWindowIcon(QIcon("./images/Python2.ico"))
        dlg.resize(430, 450)
        dlg.show()
        sys.exit(app.exec_())
    
  • 效果如下:
    在这里插入图片描述
1.2、分页查询模型
  • PyQt5 中除了上面那种可编辑的单页的列表视图,还提供了分页不可编辑的列表视图,示例如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/10/02 上午 9:10 
    # Author : 御承扬
    # e-mail:2923616405@qq.com
    # project:  PyQt5
    # File : dbOption03.py 
    # @software: PyCharm
    
    
    import sys
    import re
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtSql import *
    
    
    class DataGrid(QWidget):
        def __init__(self):
            super(DataGrid, self).__init__()
            self.setWindowIcon(QIcon("./images/Python2.ico"))
            self.setWindowTitle("分页查询示例")
            self.resize(750, 300)
            # 查询模型
            self.queryModel = None
            # 数据表
            self.tableView = None
            # 总数页文本
            self.totalPageLabel = None
            # 当前页文本
            self.currentPageLabel = None
            self.totalRecordLabel = None
            # 转到页输入框
            self.switchPageLineEdit = None
            # 前一页按钮
            self.prevButton = None
            # 后一页按钮
            self.nextButton = None
            # 转到页按钮
            self.switchPageButton = None
            # 当前页
            self.currentPage = 0
            # 总页数
            self.totalPage = 0
            # 总记录数
            self.totalRecrodCount = 0
            # 每页显示记录数
            self.PageRecordCount = 5
    
            self.db = None
            self.initUI()
    
        def initUI(self):
            self.createWindow()
            self.setTableView()
            self.prevButton.clicked.connect(self.onPrevButtonClick)
            self.nextButton.clicked.connect(self.onNextButtonClick)
            self.switchPageButton.clicked.connect(self.onSwitchPageButtonClick)
    
        def closeEvent(self, event):
            self.db.close()
    
        def createWindow(self):
            # 操作布局
            operatorLayout = QHBoxLayout()
            self.prevButton = QPushButton("前一页")
            self.nextButton = QPushButton("后一页")
            self.switchPageButton = QPushButton("Go")
            self.switchPageLineEdit = QLineEdit()
            self.switchPageLineEdit.setFixedWidth(40)
            switchPage = QLabel("转到第")
            page = QLabel("页")
            operatorLayout.addWidget(self.prevButton)
            operatorLayout.addWidget(self.nextButton)
            operatorLayout.addWidget(switchPage)
            operatorLayout.addWidget(self.switchPageLineEdit)
            operatorLayout.addWidget(page)
            operatorLayout.addWidget(self.switchPageButton)
            operatorLayout.addWidget(QSplitter())
            # 状态布局
            statusLayout = QHBoxLayout()
            self.totalPageLabel = QLabel()
            self.totalPageLabel.setFixedWidth(70)
            self.currentPageLabel = QLabel()
            self.currentPageLabel.setFixedWidth(70)
            self.totalRecordLabel = QLabel()
            self.totalRecordLabel.setFixedWidth(70)
            statusLayout.addWidget(self.totalPageLabel)
            statusLayout.addWidget(self.currentPageLabel)
            statusLayout.addWidget(QSplitter())
            statusLayout.addWidget(self.totalRecordLabel)
            # 设置表格属性
            self.tableView = QTableView()
            self.tableView.horizontalHeader().setStretchLastSection(True)
            self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
            # 创建界面
            mainLayout = QVBoxLayout(self)
            mainLayout.addLayout(operatorLayout)
            mainLayout.addWidget(self.tableView)
            mainLayout.addLayout(statusLayout)
            self.setLayout(mainLayout)
    
        def setTableView(self):
            print('*** step2 SetTableView')
            self.db = QSqlDatabase.addDatabase('QSQLITE')
            self.db.setDatabaseName('./db/datagrid.db')
            self.db.open()
            self.queryModel = QSqlQueryModel(self)
            self.currentPage = 1
            self.totalRecrodCount = self.getTotalRecordCount()
            self.totalPage = self.getPageCount()
            self.updateStatus()
            self.setTotalPageLabel()
            self.setTotalRecordLabel()
            self.recordQuery(0)
            self.tableView.setModel(self.queryModel)
            print('totalRecordCount=' + str(self.totalRecrodCount))
            print('totalPage=' + str(self.totalPage))
            self.queryModel.setHeaderData(0, Qt.Horizontal, '编号')
            self.queryModel.setHeaderData(1, Qt.Horizontal, '姓名')
            self.queryModel.setHeaderData(2, Qt.Horizontal, '性别')
            self.queryModel.setHeaderData(3, Qt.Horizontal, '年龄')
            self.queryModel.setHeaderData(4, Qt.Horizontal, '院系')
    
        def getTotalRecordCount(self):
            self.queryModel.setQuery("select * from student")
            rowCount = self.queryModel.rowCount()
            print('rowCount=' + str(rowCount))
            return rowCount
    
        def getPageCount(self):
            if self.totalRecrodCount % self.PageRecordCount == 0:
                return self.totalRecrodCount / self.PageRecordCount
            else:
                return self.totalRecrodCount / self.PageRecordCount + 1
    
        def recordQuery(self, limitIndex):
            szQuery = ("select * from student limit %d,%d" % (limitIndex, self.PageRecordCount))
            print('query sql=' + szQuery)
            self.queryModel.setQuery(szQuery)
    
        def updateStatus(self):
            szCurrentText = ("当前第%d页" % self.currentPage)
            self.currentPageLabel.setText(szCurrentText)
            if self.currentPage == 1:
                self.prevButton.setEnabled(False)
                self.nextButton.setEnabled(True)
            elif self.currentPage == self.totalPage:
                self.prevButton.setEnabled(True)
                self.nextButton.setEnabled(False)
            else:
                self.prevButton.setEnabled(True)
                self.nextButton.setEnabled(True)
    
        def setTotalPageLabel(self):
            szPageCountText = ("总共%d页" % self.totalPage)
            self.totalPageLabel.setText(szPageCountText)
    
        def setTotalRecordLabel(self):
            szTotalRecordText = ("共%d条" % self.totalRecrodCount)
            print('*** setTotalRecordLabel szTotalRecordText=' + szTotalRecordText)
            self.totalRecordLabel.setText(szTotalRecordText)
    
        def onPrevButtonClick(self):
            print('*** onPrevButtonClick ');
            limitIndex = (self.currentPage - 2) * self.PageRecordCount
            self.recordQuery(limitIndex)
            self.currentPage -= 1
            self.updateStatus()
    
        def onNextButtonClick(self):
            print('*** onNextButtonClick ');
            limitIndex = self.currentPage * self.PageRecordCount
            self.recordQuery(limitIndex)
            self.currentPage += 1
            self.updateStatus()
    
        def onSwitchPageButtonClick(self):
            # 得到输入字符串
            szText = self.switchPageLineEdit.text()
            # 数字正则表达式
            pattern = re.compile(r'^[0-9]*[1-9][0-9]*$')
            match = pattern.match(szText)
    
            # 判断是否为数字
            if not match:
                QMessageBox.information(self, "提示", "请输入数字")
                return
    
            # 是否为空
            if szText == '':
                QMessageBox.information(self, "提示", "请输入跳转页面")
                return
    
            # 得到页数
            pageIndex = int(szText)
            # 判断是否有指定页
            if pageIndex > self.totalPage or pageIndex < 1:
                QMessageBox.information(self, "提示", "没有指定的页面,请重新输入")
                return
    
            # 得到查询起始行号
            limitIndex = (pageIndex - 1) * self.PageRecordCount
    
            # 记录查询
            self.recordQuery(limitIndex);
            # 设置当前页
            self.currentPage = pageIndex
            # 刷新状态
            self.updateStatus();
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = DataGrid()
        win.show()
        sys.exit(app.exec_())
    
  • 效果如下:
    在这里插入图片描述
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

御承扬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值