PyQt5
46篇
PyQt5:极简图书管理(的使用)2
导读:正式开始啦!
LEARN MORE
正文
上期我们介绍了和的基本信息,并且通过一个视频展示了一个极简图书管理系统。本篇开始我们的正式学习。
设计思路
像这种功能相对较多的小工具,一般会先谈下设计思路。整个系统(其实就是小工具)的思路流程如下(个人思考路径,不一定*优):
1、界面设计
这个我主要是通过Qt设计师完成的。
2、功能划分:
2.1、新增图书
新增图书分为两种方式:自动读取网络图书档案、手动填写图书档案。手动填写这个不必说。自动读取网络图书档案,这个数据从哪里来呢?豆瓣API!豆瓣API提供了较为完善的图书信息,采用HTTPS访问方式,只要有图书的ISBN号,就能查询,使用非常方便。这里科普一下什么是ISBN号。国际标准书号( Book ),简称ISBN,是专门为识别图书等文献而设计的国际编号(来源:百度百科)。
为了更加方便的使用豆瓣API,我自定义了一个类,将所有有关豆瓣API的操作都放到这个类中。
2.2 查询图书
这个比较简单,根据查询的关键字段,返回具体的表格行数。
2.3 数据查询、存储
这次的程序是具有存储功能的,我们存储的载体本质是就是一个文件。通过中模块,实现图书档案的存储、删除、新增、修改等操作。这些操作我也是封装到类中,方便调用。
2.4 数据呈现
这里主要就是对进行操作了,包括修改数据、删除数据。
总结一下,如下图所示:
豆瓣API使用
豆瓣API的文档如下:
有兴趣的学友可以自己去看看,内容也比较丰富。
我们这里主要是使用读书API:
这个API的调用地址如下:
根据isbn获取图书信息
GET https://api.douban.com/v2/book/isbn/:name
同上,返回图书信息,返回status=200
这里的name就是ISBN号。
它会返回json格式的数据,类似下面这种的。
{ "id":"1220562",
"alt":"https:\/\/book.douban.com\/book\/1220562",
"rating":{"max":10, "average":"7.0", "numRaters":282, "min":0},
"author":[{"name":"片山恭一"}, {"name":"豫人"}],
"alt_title":"",
"image":"https://img3.doubanio.com\/spic\/s1747553.jpg",
"title":"满月之夜白鲸现",
"mobile_link":"https:\/\/m.douban.com\/book\/subject\/1220562\/",
"summary":"那一年,是听莫扎特、钓鲈鱼和家庭破裂的一年。说到家庭破裂,母亲怪自己当初没有找到好男人,父亲则认为当时是被狐狸精迷住了眼,失常的是母亲,但出问题的是父亲……。",
"attrs":{
"publisher":["青岛出版社"],
"pubdate":["2005-01-01"],
"author":["片山恭一", "豫人"],
"price":["18.00元"],
"title":["满月之夜白鲸现"],
"binding":["平装(无盘)"],
"translator":["豫人"],
"pages":["180"]
},
"tags":[
{"count":106, "name":"片山恭一"},
{"count":50, "name":"日本"},
{"count":42, "name":"日本文学"},
{"count":30, "name":"满月之夜白鲸现"},
{"count":28, "name":"小说"},
{"count":10, "name":"爱情"},
{"count":7, "name":"純愛"},
{"count":6, "name":"外国文学"}
]
}
这个和当中的字典是不是很像,然后我们将其转换成字典,并取得相应的数据。下面我们来具体的看一下相应的代码。
class GetBookInfo:
def __init__(self, isbn):
if isbn == "":
self.isbn = "1234567890123"
else:
self.isbn = isbn
def getbookinfo(self):
"""
利用豆瓣API读取图书信息
"""
url = "https://api.douban.com/v2/book/isbn/:" + self.isbn
header = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36"
}
r = requests.get(url, headers = header)
info = r.text
bookinfo_dic = json.loads(info)
bookinfo = {"subtitle" : "", "author": "", "pubdate" : "", "classification" : "",
"publisher" : "", "price" : "", "pages" : "", "summary" : "", "img" : "", "country" : ""
}
if bookinfo_dic.get("code"):
rstatus = "0"
return rstatus, bookinfo
else:
rstatus = "1"
subtitle = bookinfo_dic["title"]
author = " ".join(bookinfo_dic["author"])
pubdate = bookinfo_dic["pubdate"]
classification = bookinfo_dic["tags"][0]["title"]
publisher = bookinfo_dic["publisher"]
price = bookinfo_dic["price"]
pages = bookinfo_dic["pages"]
summary = bookinfo_dic["summary"]
img = bookinfo_dic["images"]["small"].replace("\\", "")
if author[0] == "[":
country = author[1]
else:
country = "中"
bookinfo = {"subtitle" : subtitle, "author": author, "pubdate" : pubdate, "classification" : classification,
"publisher" : publisher, "price" : price, "pages" : pages, "summary" : summary, "img" : img, "country" : country
}
return rstatus, bookinfo
为节约篇幅,主要把()函数讲一下。
url = "https://api.douban.com/v2/book/isbn/:" + self.isbn
header = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36"}
r = requests.get(url, headers = header)
info = r.text
这几句话是利用第三方库以及豆瓣API获取图书信息,至于库的使用,相应的教程百度上已经烂大街了,可以自己看看。这里放上中文版的帮助文档。
bookinfo_dic = json.loads(info)
将获取的json数据转换成字典格式,这样就能操作了。它还有一个姊妹函数,如下:
json.dumps()#将 Python 对象编码成 JSON 字符串
bookinfo = {"subtitle" : "", "author": "", "pubdate" : "", "classification" : "",
"publisher" : "", "price" : "", "pages" : "", "summary" : "", "img" : "", "country" : ""
}
这个字典是用于存储图书信息的,分别对应图书的名称、作者、出版日期、分类、出版单位、价格、页数、内容简介、封面、作者国家。
if bookinfo_dic.get("code"):
rstatus = "0"
return rstatus, bookinfo
else:
rstatus = "1"
subtitle = bookinfo_dic["title"]
author = " ".join(bookinfo_dic["author"])
pubdate = bookinfo_dic["pubdate"]
classification = bookinfo_dic["tags"][0]["title"]
publisher = bookinfo_dic["publisher"]
price = bookinfo_dic["price"]
pages = bookinfo_dic["pages"]
summary = bookinfo_dic["summary"]
img = bookinfo_dic["images"]["small"].replace("\\", "")
if author[0] == "[":
country = author[1]
else:
country = "中"
bookinfo = {"subtitle" : subtitle, "author": author, "pubdate" : pubdate, "classification" : classification,
"publisher" : publisher, "price" : price, "pages" : pages, "summary" : summary, "img" : img, "country" : country
}
return rstatus, bookinfo
这里做了一个判断,如果我们读取图书数据的时候,其返回值包含code这个字段,且code = 0,表明我们获取数据失败,可能是ISBN号不对等情况。否则将图书信息存入这个字典当中。这里需要注意两点:
1、国家信息是我自己增加的,API中没有明确的显示出来,注意是根据作者信息判断出来的,国外的作者名称前面都带有[]符号,如下图:
if author[0] == "[":
country = author[1]
else:
country = "中"
2、封面的链接是需要修改的,不能直接拿来用,因为它是这样的:
"https://img1.doubanio.com\/view\/subject\/s\/public\/s29745409.jpg"
我们需要吧链接当中的“\”替换成空字符串””,所以有了如下的代码:
img = bookinfo_dic["images"]["small"].replace("\\", "")
数据存储
所有的数据操作类是存放到这个类当中的,我们所有的图书档案数据载入到数据内存中,是存储到这个列表变量。这个列表变量中每一个元素是一个字典,即每本图书的档案信息,如:书名、作者、出版日期之类的。
在这里我们选择存储的方式是的模块,为什么选择模块。
如果我们这样操作:
list = [1,2,3]
f = open("xx.dat","w")
f.write(list)
f.close()
执行即报错:
Traceback (most recent call last):
File "C:\Users\Administrator\Desktop\66666666.py", line 6, in
f.write(list)
TypeError: write() argument must be str, not list
但是使用就不会。
import pickle
list = [1,2,3]
f = open("xx.dat","wb")
pickle.dump(list, f)
f.close()
能够存储列表,使用十分方便。
好吧,我们来看看相应的代码。
class DataManagement:
books = []
def insert_db(self, bookinfo):
self.books = self.load()
for book in self.books:
if book["isbn"] == bookinfo["isbn"]:
return -1
else:
self.books.append(bookinfo)
with codecs.open("book.dat", "wb") as f:
pickle.dump(self.books, f)
return 1
def save_db(self, bookinfoes):
with codecs.open("book.dat", "wb") as f:
pickle.dump(bookinfoes, f)
def query_db(self, isbn = "",author = "",bookname = ""):
self.books = self.load()
if isbn:
for i, book in enumerate(self.books):
if book["isbn"] == isbn:
return i
else:
return -1
if author:
for i, book in enumerate(self.books):
if book["author"] == author:
return i
else:
return -1
if bookname:
for i, book in enumerate(self.books):
if book["subtitle"] == bookname:
return i
else:
return -1
def load(self):
pathname = "book.dat"
if not(os.path.exists(pathname) and os.path.isfile(pathname)):
with codecs.open("book.dat", "wb") as f:
pickle.dump(self.books, f)
with codecs.open("book.dat", "rb") as f:
books = pickle.load(f)
return books
这个类中我们建立几个函数:
1、:插入一条图书数据
2、:保存所有图书档案
3、:查找图书
4、load:载入数据
def load(self):
pathname = "book.dat"
if not(os.path.exists(pathname) and os.path.isfile(pathname)):
with codecs.open("book.dat", "wb") as f:
pickle.dump(self.books, f)
with codecs.open("book.dat", "rb") as f:
books = pickle.load(f)
return books
存储数据之前先要载入数据。我们先判断数据存储的文件“book.dat”是否存在,不存在的话我们就新建一个,利用.dump()函数新建。
然后我们打开“book.dat”,使用.load()载入列表,并返回列表books。
有关的文章,之前写过一篇,不过是在环境下,在中已经没有了,但是用法上大部分通用。可以参考:
def insert_db(self, bookinfo):
self.books = self.load()
for book in self.books:
if book["isbn"] == bookinfo["isbn"]:
return -1
else:
self.books.append(bookinfo)
with codecs.open("book.dat", "wb") as f:
pickle.dump(self.books, f)
return 1
这个函数中参数表示一条图书档案信息,即一本书的信息。
这里我们做了一个判断,如果插入的ISBN号是存在的返回-1。如果遍历全部图书信息都是不存在的,那么,我们给self.books这一列表中新增一个图书信息,并保存到“book.dat”中,同时返回1,表示保存没有问题。有关for……else的用法,可以参考这篇文章:
def query_db(self, isbn = "",author = "",bookname = ""):
self.books = self.load()
if isbn:
for i, book in enumerate(self.books):
if book["isbn"] == isbn:
return i
else:
return -1
if author:
for i, book in enumerate(self.books):
if book["author"] == author:
return i
else:
return -1
if bookname:
for i, book in enumerate(self.books):
if book["subtitle"] == bookname:
return i
else:
return -1
这里我们可以根据ISBN、作者、书名来查找图书,要是找到了就返回这本书在self.books中的位置,如果没有找到返回-1。
def save_db(self, bookinfoes):
with codecs.open("book.dat", "wb") as f:
pickle.dump(bookinfoes, f)
这个函数比较好理解,就是保存整个图书档案。这里的是整个图书档案的列表。
*后
总结下我们今天的内容:
1、程序设计思路
2、豆瓣API使用
3、数据存储