PyQt4百行代码自制密码管理器(三):数据库引入

我们在这里使用的是一个轻量级数据库sqlite。Python2.5.x以上的版本默认自带了sqlite3,大家可以试一下如果能成功import sqlite3就ok了。
首先我们需要一些预备知识。操作数据库中的数据需要学习一种叫做SQL的语言,推荐w3school的教程:
http://www.w3school.com.cn/sql/
不需要系统学习,简单了解一下就好。然后还需要学习一下sqlite在python中的基本操作方法,教程在这里:
http://www.runoob.com/sqlite/sqlite-python.html
有了数据库的知识,我们先来完成initDB()函数,完成每次程序启动后都需要做的一些初始化操作。注意,现在我们的current_row就不能初始化为0了,所以__init__(self)函数中self.current_row = 0这一句就没什么用了,可以删去。还有,这里我们使用了os.path.exists()函数,所以需要额外导入os包:import os。

initDB()

def initDB(self):
    if os.path.exists('info.db'):
        self.conn = sqlite3.connect('info.db')
        self.conn.isolation_level = None
    else:
        self.conn = sqlite3.connect('info.db')
        self.conn.isolation_level = None
        self.conn.execute('''CREATE TABLE INFO
                    (ID int PRIMARY KEY NOT NULL,
                    WEBSITE char(255),
                    USERNAME char(255),
                    PASSWORD char(255),
                    URL char(255))''')
    cur = self.conn.cursor()
    cur.execute('SELECT * FROM INFO')
    self.displayData = cur.fetchall()
    cur.close()
    self.current_row = len(self.displayData)

前面比较好理解,如果存在这个数据库,就和它建立联系;如果不存在的话,就新建一个。

self.conn.isolation_level = None

这里我们修改隔离等级是为了图方便,每次对数据库操作之后不用commit就可以生效。
注意我们每个项目除了之前的四个数据之外,还加入了’ID’这一数据,ID为数据所处的行数(从1开始计数),目的是通过给每条数据编号的方式使查找某一行的数据变得简单,我们后面就会看到。

cur = self.conn.cursor()
cur.execute('SELECT * FROM INFO')
self.displayData = cur.fetchall()
cur.close()
self.current_row = len(self.displayData)

这里我们建立了一个游标(cursor),用来读取已经在数据库中的数据,并且获得数据的条数。
接下来,我们需要修改之前已经写好的三个分别具有new、edit、delete功能的函数,使用户进行的操作可以同步修改数据库中的数据。
新版newAction_def()

def newAction_def(self):
    data = self.showDialog()
    if data[0]:
        self.current_row += 1
        self.conn.execute("INSERT INTO INFO VALUES(%d, '%s', '%s', '%s', '%s')"
                          % (self.current_row, data[1], data[2], data[3], data[4]))
        self.grid.insertRow(self.current_row - 1)
        for i in range(4):
            new_item = QtGui.QTableWidgetItem(data[i + 1])
            self.grid.setItem(self.current_row - 1, i, new_item)

这里我们用SQL中的insert语句将新的数据插入数据库内。同样,注意区分清楚行数和行号。
另外注意,%s两边的单引号必须带,想一想为什么。

新版editAction_def()

def editAction_def(self):
    selected_row = self.grid.selectedItems()
    if selected_row:
        edit_row = self.grid.row(selected_row[0])
        old_data = []
        for i in range(4):
            old_data.append(self.grid.item(edit_row, i).text())
        new_data = self.showDialog(*old_data)
        if new_data[0]:
            self.conn.execute('''UPDATE INFO SET
                             WEBSITE = '%s', USERNAME = '%s',
                             PASSWORD = '%s', URL = '%s'
                             WHERE ID = '%d' '''
                          % (new_data[1], new_data[2], new_data[3], new_data[4], edit_row + 1))
            for i in range(4):
                new_item = QtGui.QTableWidgetItem(new_data[i + 1])
                self.grid.setItem(edit_row, i, new_item)
    else:
        self.showHint()

修改操作同样也比较简单,我们使用ID查找到要修改的数据,在数据库、窗口中分别修改它。

新版delAction_def()

def delAction_def(self):
    selected_row = self.grid.selectedItems()
    if selected_row:
        del_row = self.grid.row(selected_row[0])
        self.grid.removeRow(del_row)
        print del_row
        self.conn.execute("DELETE FROM INFO WHERE ID = %d" % (del_row + 1))
        for index in range(del_row + 2, self.current_row + 1):
            self.conn.execute("UPDATE INFO SET ID = %d WHERE ID = %d" % ((index - 1), index))
        self.current_row -= 1
    else:
        self.showHint()

而del函数就要注意了,删除某项之后,其后项目ID并不会自动改变,我们需要手动把后面的项目序号-1……就是下面这两句:

for index in range(del_row + 2, self.current_row + 1):
    self.conn.execute("UPDATE INFO SET ID = %d WHERE ID = %d" % ((index - 1), index))

顺求更好方法解决这个问题。
最后,我们在程序结束后关闭数据库,于是我们将main函数改成这样:

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    pwk = PWKeeper()
    pwk.show()
    app.exec_()
    pwk.conn.close()
    sys.exit(0)

大功告成

这样我们就大功告成啦!试着运行一下自己的密码管理器,尝试一下各种功能是否正常。关闭程序后,我们可以看见程序所在目录下出现了一个.db的数据库文件。
至此,我们已经完成了实现密码管理器功能的所有代码,有没有很大的成就感呢!
程序设计中,代码并不是最重要的,我们更需要掌握一些思想方法和学习方法,所以请务必阅读一下看似没有什么用的下一节。
【持续更新中】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章