为了更好的学习与数据库相关的例子,这里我们选择了之前已经完成过的一个例子:极简图书管理,对其进行适当的改写,将数据存入数据库中。
程序结构
程序功能划分
程序类的划分
功能演示
数据库
这些都是存在数据库中的数据,如下图:
和我们在程序中的图书数据是一致的,如下图:
运行结果
新增图书新增图书https://www.zhihu.com/video/1017728892139888640
点击显示图书详情点击有详情https://www.zhihu.com/video/1017728971018006528
修改图书修改图书https://www.zhihu.com/video/1017729054933417984
删除图书删除图书https://www.zhihu.com/video/1017729176392036352
删除图书后的数据库
查找图书查找图书https://www.zhihu.com/video/1017729310391721984
部分核心代码讲解
核心代码部分重点讲解数据库操作这块,其它部分在之前的学点编程吧:PyQt5系列教程(46):极简图书管理(QTableWidget的使用)1zhuanlan.zhihu.com学点编程吧:PyQt5系列教程(47):极简图书管理(QTableWidget的使用)2zhuanlan.zhihu.com学点编程吧:PyQt5系列教程(48):极简图书管理(QTableWidget的使用)3zhuanlan.zhihu.com学点编程吧:PyQt5系列教程(49):极简图书管理(QTableWidget的使用)4zhuanlan.zhihu.com
已经介绍过了。
原理介绍
在正式开始讲解之前,我们还是来简单的介绍以下PyQt5的MVC编程。
程序设计当中有一个设计模式叫做MVC(Model-View-Controller)设计模式,即模型-视图-控制。这是一种非常典型的设计模式,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
部分来源:百度百科
在PyQt中将视图与控制结合在一起,同时添加了代理delegate能够自定义数据条目item的显示与编辑方式。这仍然将数据存储的方式与呈现给用户的方式分开,但是基于相同的原则提供了更简单的框架。
这种分离使得可以在几个不同的视图中显示相同的数据,并实现新类型的视图,而无需更改基础数据结构。 为了灵活处理用户输入,我们引入了delegate(代理或者叫委托,下面统一称为委托)的概念。
在这个框架中拥有一个委托的好处是,它允许对数据项目的呈现和编辑进行自定义。
整体体系结构如下:
该模型与数据源通信,为架构中的其他组件提供接口。 通信的性质取决于数据源的类型以及模型的实施方式。
该视图从模型中获得模型索引;这些是对数据项的引用。 通过向模型提供模型索引,视图可以从数据源中检索数据项。
在标准视图中,委托呈现数据项。 编辑项目时,委托使用模型索引直接与模型进行通信。
所以,我们在本次的设计中,我们使用setModel()设定数据模型,用来确定数据来源;而使用setItemDelegate()函数为我们数据过滤,生成我们想要的表现显示。
大致样式:
数据模型
本期我们先来介绍下数据模型。
class BookSqlTableModel(QSqlTableModel):
def __init__(self):
super().__init__()
def data(self, index, role):
if index.isValid():
if role == Qt.TextAlignmentRole:
return QVariant(Qt.AlignHCenter | Qt.AlignVCenter)
if role == Qt.DecorationRole and index.column() == 0:
countryName = index.data()
countryIconPath = self.getCountry(countryName)
return QVariant(countryIconPath)
else:
return super().data(index, role)
def getCountry(self, countryName):
if countryName == "中":
countryIcon = QIcon("./res/countries/china.png")
elif countryName == "英":
countryIcon = QIcon("./res/countries/english.png")
elif countryName == "日":
countryIcon = QIcon("./res/countries/japan.png")
elif countryName == "俄":
countryIcon = QIcon("./res/countries/russian.png")
elif countryName == "美":
countryIcon = QIcon("./res/countries/usa.png")
elif countryName == "智":
countryIcon = QIcon("./res/countries/chile.png")
else:
countryIcon = QIcon("./res/countries/default.png")
return countryIcon
我们在QQ模拟那期当中介绍了,QListView如何使用模型来加载数据的,这个也是一样。我们通过继承QSqlTableModel自定义一个模型类,重写data(),实现数据的来源。
QSqlTableModel类为单个数据库表提供可编辑的数据模型。
QSqlTableModel是一个高级接口,用于从单个表读取和写入数据库记录。它构建在较低级别的QSqlQuery之上,可用于提供数据以查看诸如QTableView之类的类。例如:
model = QSqlTableModel(parentObject, database)
model.setTable("employee")
model.setEditStrategy(QSqlTableModel.OnManualSubmit)
model.select()
model.setHeaderData(0, Qt.Horizontal, "Name")
model.setHeaderData(1, Qt.Horizontal, "Salary")
view = QTableView()
view.setModel(model)
view.hideColumn(0) #不显示ID
view.show()
我们设置SQL表的名称和编辑策略,然后设置视图标题中显示的标签。编辑策略指示用户在视图中完成的更改实际应用于数据库的时间。可能的值有OnFieldChange,OnRowChange和OnManualSubmit,具体意思后期介绍。
QSqlTableModel还可用于以编程方式访问数据库,而无需将其绑定到视图:
model = QSqlTableModel()
model.setTable("employee")
model.select()
salary = model.record(4).value("salary")
上面的代码片段从employee中查询SELECT *的结果集中的记录4中提取工资字段。
可以使用setFilter()设置过滤器,或使用setSort()修改排序顺序。最后,您必须调用select()以使用数据填充模型。
QSqlTableModel不提供对外键的直接支持。如果要解析外键,请使用QSqlRelationalTableModel和QSqlRelationalDelegate。
def data(self, index, role):
if index.isValid():
if role == Qt.TextAlignmentRole:
return QVariant(Qt.AlignHCenter | Qt.AlignVCenter)
if role == Qt.DecorationRole and index.column() == 0:
countryName = index.data()
countryIconPath = self.getCountry(countryName)
return QVariant(countryIconPath)
else:
return super().data(index, role)
上面这个函数的意思就说:在模型索引存在的情况下,我们表格中数据排列是垂直、水平居中;同时在第一列的数据中,我们需要返回一个图标。这个图标是根据第一列的数据来选择的。其他情况使用父类QSqlTableModel的默认数据。
def getCountry(self, countryName):
if countryName == "中":
countryIcon = QIcon("./res/countries/china.png")
elif countryName == "英":
countryIcon = QIcon("./res/countries/english.png")
elif countryName == "日":
countryIcon = QIcon("./res/countries/japan.png")
elif countryName == "俄":
countryIcon = QIcon("./res/countries/russian.png")
elif countryName == "美":
countryIcon = QIcon("./res/countries/usa.png")
elif countryName == "智":
countryIcon = QIcon("./res/countries/chile.png")
else:
countryIcon = QIcon("./res/countries/default.png")
return countryIcon
这个是根据国家名称返回对应的国旗图标,比较简单,不做讲解。
最后
好的,今天这期就这样结束吧。下期我们再继续。如果你喜欢本篇文章,请给我点赞
赞赏(推荐)
分享给你的好友们吧!
欢迎关注微信公众号:学点编程吧。加油!(ง •̀_•́)ง (*•̀ㅂ•)
实操中有问题?来讨论吧!学点编程吧-百度贴吧--计算机程序学习的园地!--学点编程吧,让我们的生活更简单,更高效!能用计算机解决的事情,尽量不要让人解决。如果你在学习当中有任何疑问、学习心得、职业发展等内容欢迎在贴吧中分享,让我tieba.baidu.com