前言与准备
本次实验是大二数据库期末大作业,我采用的是python语言和mysql8.0.27制作的基于cs构架的数据库框架,由于之前从未了解过python语言,所以代码部分语言较为粗暴,未成年人请在父母陪同下观看(狗头) ,至于mysql的安装与基本使用,在网络上的教程较多,可自行查找。
本次代码编写,我分成了3个部分,即分别编写登录界面、用户界面和管理员界面的代码,最后在利用一个统一的变量参数来串联起来,而由于代码能力的限制,不是我懒 ,最后仅仅实现了本地使用,至于联机的应用,交给各位自行探索,顺便学会后给我发份代码 。
登录界面
登录界面的设计较为简单,或者说整个实验的代码都是同一个道理的堆砌,并没有太多不同。
首先是学会python与mysql的连接,我使用的是pymysql这个模块,之后便在界面对应按钮上提供函数即可,如登录按钮,则在读取数据库后穷举其中的账号密码与输入的账号密码做比较即可,如下:
def auto_login():
# 连接数据库
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
# 获取操作游标
cur = db.cursor()
# 查询数据库
sql = 'select * from user'
entry1 = input1.get()
entry2 = input2.get()
flag = False
cur.execute(sql) # 执行查询
results = cur.fetchall() # 获取所有查询数据
global username
for row in results:
uid = row[3] # 账号
pwd = row[4] # 密码
# 判断输入的账号和密码是否正确
if entry1 == uid and entry2 == pwd:
print('登录成功')
username = row[0]
success(username)
flag = True
break
if flag == False:
sql = 'select * from admin'
cur.execute(sql) # 执行查询
results = cur.fetchall() # 获取所有查询数据
for row in results:
uid = row[0] # 账号
pwd = row[1] # 密码
# 判断输入的账号和密码是否正确
if entry1 == uid and entry2 == pwd:
print('登录成功')
username = row[0]
success(username)
flag = True
break
if flag == False:
fail()
cur.close()
db.commit()
db.close()
代码中之所以穷举了两次,是因为我的代码分别考虑了用户和管理员两套不同的账号,但其实原理一样。不要忙着复制上方代码,因为下面有全套的。
from tkinter import *
import tkinter.ttk
from tkinter.messagebox import *
from ttkbootstrap import Style
import pymysql
import datetime
from PIL import Image, ImageTk
def success(username):
root.destroy()
root1 = Tk()
root1.withdraw()
showinfo('登录成功', username + ',欢迎您')
root1.destroy()
return True
def fail():
showerror('登录失败', '用户名或密码错误')
return False
def auto_login():
# 连接数据库
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
# 获取操作游标
cur = db.cursor()
# 查询数据库
sql = 'select * from user'
entry1 = input1.get()
entry2 = input2.get()
flag = False
cur.execute(sql) # 执行查询
results = cur.fetchall() # 获取所有查询数据
global username
for row in results:
uid = row[3] # 账号
pwd = row[4] # 密码
# 判断输入的账号和密码是否正确
if entry1 == uid and entry2 == pwd:
print('登录成功')
username = row[0]
success(username)
flag = True
break
if flag == False:
sql = 'select * from admin'
cur.execute(sql) # 执行查询
results = cur.fetchall() # 获取所有查询数据
for row in results:
uid = row[0] # 账号
pwd = row[1] # 密码
# 判断输入的账号和密码是否正确
if entry1 == uid and entry2 == pwd:
print('登录成功')
username = row[0]
success(username)
flag = True
break
if flag == False:
fail()
cur.close()
db.commit()
db.close()
def exit_login():
root.destroy()
pass
def regist(ip1, ip21, ip22, ip23, ip3, ip4, ip5):
if ip1.get() == '' or ip21.get() == '' or ip22.get() == '' or ip23.get() == '' or ip3.get() == '' or ip4.get() == '' or ip5.get() == '':
showerror('注册失败', '请填写全部内容')
return
if ip4.get() != ip5.get():
showerror('注册失败', '密码输入不一致')
return
if ip22.get() == 1 or ip22.get() == 3 or ip22.get() == 5 or ip22.get() == 7 or ip22.get() == 8 or ip22.get() == 10 or ip22.get() == 12:
if ip23.get() < 1 or ip23.get() > 31:
showerror('注册失败', '日期有误')
if ip22.get() == 4 or ip22.get() == 6 or ip22.get() == 9 or ip22.get() == 11:
if ip23.get() < 1 or ip23.get() > 30:
showerror('注册失败', '日期有误')
if ip22.get() == 2:
if ip23.get() < 1:
showerror('注册失败', '日期有误')
if ip21.get() % 4 == 0 and ip23.get() > 29:
showerror('注册失败', '日期有误')
if ip21.get() % 4 != 0 and ip23.get() > 28:
showerror('注册失败', '日期有误')
today = datetime.datetime.today()
if today.year - int(ip21.get()) > 100:
showerror('注册失败', '日期有误')
if ip3.get() != '男' and ip3.get() != '女':
showerror('注册失败', '性别有误')
bir = datetime.datetime.date(
datetime.datetime.strptime(ip21.get() + '-' + ip22.get() + '-' + ip23.get(), '%Y-%m-%d'))
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
cur = db.cursor()
sql = 'select * from user'
cur.execute(sql)
results = cur.fetchall()
i = 0
for row in results:
i = i + 1
if row[0] == ip1.get() and row[1] == ip3.get() and row[2] == bir:
showerror('注册失败', '该账号已存在')
return
id = str(int(results[-1][3]) + 1)
sql = "insert into user values (%s, %s, %s, %s, %s,%s,%s)"
data = (ip1.get(), ip3.get(), bir, id, ip4.get(),None,None)
cur.execute(sql, data)
showinfo('注册成功', ip1.get() + ',\n您的账号为' + id)
cur.close()
db.commit()
db.close()
def regist_login():
root1 = Toplevel(root)
root1.title('用户注册')
root1.geometry('400x400+500+300')
root1.iconbitmap('start.ico')
Label(root1, text='欢迎注册本系统').place(relx=0.2, rely=0.04)
Label(root1, text='姓名:').place(relx=0.05, rely=0.15)
Label(root1, text='出生日期:').place(relx=0.05, rely=0.3)
Label(root1, text='年').place(relx=0.2, rely=0.36)
Label(root1, text='月').place(relx=0.5, rely=0.36)
Label(root1, text='日').place(relx=0.8, rely=0.36)
Label(root1, text='性别:').place(relx=0.05, rely=0.45)
Label(root1, text='请输入密码:').place(relx=0.05, rely=0.6)
Label(root1, text='请再次输入密码:').place(relx=0.05, rely=0.75)
v1 = StringVar()
v21 = StringVar()
v22 = StringVar()
v23 = StringVar()
v3 = StringVar()
v4 = StringVar()
v5 = StringVar()
input1 = Entry(root1, textvariable=v1)
input1.place(relx=0.05, rely=0.21)
input21 = Entry(root1, textvariable=v21)
input21.place(relx=0.05, rely=0.36, width=55)
input22 = Entry(root1, textvariable=v22)
input22.place(relx=0.3, rely=0.36, width=55)
input23 = Entry(root1, textvariable=v23)
input23.place(relx=0.55, rely=0.36, width=55)
input3 = tkinter.ttk.Combobox(root1, textvariable=v3, values=['男', '女'])
input3.place(relx=0.05, rely=0.51, relwidth=0.2, relheight=0.08)
input3.current(0)
input4 = Entry(root1, textvariable=v4, show='*')
input4.place(relx=0.05, rely=0.66)
input5 = Entry(root1, textvariable=v5, show='*')
input5.place(relx=0.05, rely=0.81)
Button(root1, text='注册', width=10,
command=lambda: regist(input1, input21, input22, input23, input3, input4, input5)).place(relx=0.1, rely=0.9)
Button(root1, text='返回', width=10, command=root1.destroy).place(relx=0.5, rely=0.9)
def pwd(ip1, ip21, ip22, ip23, ip3, ip4):
bir = datetime.datetime.date(
datetime.datetime.strptime(ip21.get() + '-' + ip22.get() + '-' + ip23.get(), '%Y-%m-%d'))
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
cur = db.cursor()
sql = 'select * from user'
cur.execute(sql)
results = cur.fetchall()
flag = False
for row in results:
if row[0] == ip1.get() and row[1] == ip3.get() and row[2] == bir and row[3] == ip4.get():
flag = True
showinfo('成功找到', '您的密码为:' + row[4])
root2.destroy()
break
if flag == False:
showerror('找回失败', '请核实信息')
cur.close()
db.commit()
db.close()
def pwd_login():
global root2
root2 = Toplevel(root)
root2.title('找回密码')
root2.geometry('400x400+500+300')
root2.iconbitmap('start.ico')
Label(root2, text='姓名:').place(relx=0.05, rely=0.15)
Label(root2, text='出生日期:').place(relx=0.05, rely=0.3)
Label(root2, text='年').place(relx=0.2, rely=0.36)
Label(root2, text='月').place(relx=0.5, rely=0.36)
Label(root2, text='日').place(relx=0.8, rely=0.36)
Label(root2, text='性别:').place(relx=0.05, rely=0.45)
Label(root2, text='id:').place(relx=0.05, rely=0.6)
v1 = StringVar()
v21 = StringVar()
v22 = StringVar()
v23 = StringVar()
v3 = StringVar()
v4 = StringVar()
input1 = Entry(root2, textvariable=v1)
input1.place(relx=0.05, rely=0.21)
input21 = Entry(root2, textvariable=v21)
input21.place(relx=0.05, rely=0.36, width=55)
input22 = Entry(root2, textvariable=v22)
input22.place(relx=0.3, rely=0.36, width=55)
input23 = Entry(root2, textvariable=v23)
input23.place(relx=0.55, rely=0.36, width=55)
input3 = tkinter.ttk.Combobox(root2, textvariable=v3, values=['男', '女'])
input3.place(relx=0.05, rely=0.51, relwidth=0.2, relheight=0.08)
input3.current(0)
input4 = Entry(root2, textvariable=v4, )
input4.place(relx=0.05, rely=0.66)
Button(root2, text='确定', width=10,
command=lambda: pwd(input1, input21, input22, input23, input3, input4)).place(relx=0.1, rely=0.9)
Button(root2, text='返回', width=10, command=root2.destroy).place(relx=0.5, rely=0.9)
def frame():
global root
style = Style(theme="yeti")
root = style.master
root.title('登录窗口')
root.geometry('960x640+420+200')
root.resizable(0, 0)
root.iconbitmap('start.ico')
v1 = StringVar()
v2 = StringVar()
img = Image.open('登录.jpg')
img = img.resize((960, 640)) # 修改图片大小
photo = ImageTk.PhotoImage(img)
Label(root, image=photo, compound=CENTER).pack()
# 账号标签,位置在第0行第0列
Label(root, text='账号:', bg='lightskyblue', fg='white', font=(16)).place(relx=0.35, rely=0.3)
# 密码标签,位置在第1行第0列
Label(root, text='密码:', bg='lightskyblue', fg='white', font=(16)).place(relx=0.35, rely=0.4)
# 账号输入框
global input1
input1 = Entry(root, textvariable=v1, highlightthickness=1, highlightcolor='lightskyblue', relief='groove')
input1.place(relx=0.42, rely=0.31)
# 密码输入框
global input2
input2 = Entry(root, textvariable=v2, highlightthickness=1, highlightcolor='lightskyblue', relief='groove',
show='*')
input2.place(relx=0.42, rely=0.41)
# 登录按钮
Button(root, text='登录', width=10, command=auto_login).place(relx=0.35, rely=0.5)
# 退出按钮
Button(root, text='退出', width=10, command=exit_login).place(relx=0.55, rely=0.5)
# 注册按钮
Button(root, text='注册', width=10, command=regist_login).place(relx=0.35, rely=0.65)
# 找回密码
Button(root, text='找回密码', width=10, command=pwd_login).place(relx=0.55, rely=0.65)
root.mainloop()
if __name__ == '__main__':
frame()
上方为登录界面的代码,每个函数的作用分别在按钮处名字体现,其中需要注意的是在输入日期时要考虑到mysql的日期格式问题,因此在注册处的日期,包括之后的借书日期等都有格式转化的过程。
如果你认真分析了上面的代码,并认为做到这个地步已经够了或不够的兄弟们,可以关闭该文章了。因为剩下两部分的代码本质上只是在重复这个过程,只是将图片、按钮进行更改,你可以自己设计了,而不满足与此的兄弟,我也帮不了你,你可以不要浪费时间了。
以下内容均为水字数
用户界面
用户界面整体上我分为3个部分,分别是公告、书库、用户,这3部分的实现是利用ttk.Notebook实现的,具体的用法可以自行查阅。
公告
本部分是利用了mysql存储长文本的能力实现的,利用tkinter的text在管理员处存入文本,再在数据库中读出利用text显示在用户处(增加不可修改的状态),下方为图片,代码再用户界面最后。
书库
书库中用到最重要的一个功能是tkinter中的tree,它可以在界面中增加一个表格,具体功能请自行查阅。书库所实现的两大部分之一查书,就是利用不同条件查询的书籍显示在表格中。其中在搜书过程中,实现了一次搜书与多次搜书,所谓多次搜书,是利用上一次搜书的结果进行再次搜索。一次与多次搜索均为模糊搜索,即支持关键字乃至间隔字(如输入“三义”出现三国演义)。一次搜索是利用了数据库查询的like与%,而多次搜索则是将当前表格中的书籍与搜索内容比较,python中的fuzzywuzzy模块实现。
另外一大部分是借书,我利用鼠标绑定,在鼠标按键中获取书名,并根据其是否已被借阅、是否丢失判断是否可借,可借则在借阅数据库中增加数据,如获取电脑时间确定结束时间,增加30天作为应还书时间。
用户
用户界面在左侧边栏设置按钮指向不同的界面,其本质是右侧的标签是否显示,利用pack进行控制,在点击某一按钮时,就将其对应标签设置为可见,其他隐藏即可。特附代码:
def changeTag(user, tag=0):
frame0.pack_forget()
frame2.pack_forget()
if tag == 0:
frame0.pack(padx=1, pady=1, ipadx=500, ipady=500)
elif tag == 2:
frame2.pack(padx=1, pady=1, ipadx=500, ipady=500)
x = tree2.get_children()
for item in x:
tree2.delete(item)
jie_book(user)
其他的部分只需将自己的想法写出即可。如还书部分可增加异常还书,选择书籍丢失或损坏后赔偿相应的损失,在例如根据其还书时间与设置的应还书时间判断是否违约,违约还可设置对应标志来减少其可借数量(我未实现,懒)。
下方为用户部分全代码(当时懒得写注释,尽力观看)
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import *
import tkinter.ttk
from ttkbootstrap import Style
import pymysql
from fuzzywuzzy import fuzz
from PIL import Image, ImageTk
import datetime
def text_1():
text1.tag_config("tag_1", foreground="blue", font=(20))
text1.tag_config("tag_2", foreground="blue", font=(12))
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
cur = db.cursor()
sql = 'select * from texts'
cur.execute(sql)
data = cur.fetchall()
if data == ():
text1.insert(INSERT, '暂无新公告', 'tag_1')
else:
text1.insert(INSERT, data[-1][1], 'tag_2')
text1.insert(INSERT, '\n')
text1.insert(INSERT, data[-1][0], 'tag_1')
cur.close()
db.close()
def text_3():
text3.tag_config("tag_1", foreground="blue", font=(20))
text3.tag_config("tag_2", foreground="blue", font=(12))
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
cur = db.cursor()
sql = 'select * from recommend'
cur.execute(sql)
data = cur.fetchall()
if data == ():
text3.insert(INSERT, '暂无新公告', 'tag_1')
else:
text3.insert(INSERT, data[-1][1], 'tag_2')
text3.insert(INSERT, '\n')
text3.insert(INSERT, data[-1][0], 'tag_1')
cur.close()
db.close()
def find(t):
db = pymysql.connect(host='localhost', user='root', password='159357', db='sdusql', port=3306)
cur = db.cursor()
if var.get() == '书名':
sql = """ select * from book where bname like %s """
t2 = ''
for i in range(len(t.get())):
t2 = t2 + t.get()[i] + '%'
params = '%' + t2
if cur.execute(sql, params) == 0:
showerror('查询失败', '请核实您输入的内容')
else:
x = tree.get_children()
for item in x:
tree.delete(item)
result = cur.fetchall()
for i in result:
tree.insert('', 'end', values=i)
if var.get() == 'ISBN':
sql = """ select * from book where ISBN like %s """
t2 = ''
for i in range(len(t.get())):
t2 = t2 + t.get()[i] + '%'
params = '%' + t2
if cur.execute(sql, params) == 0:
showerror('查询失败', '请核实您输入的内容')
else:
x = tree.get_children()
for item in x:
tree.delete(item)
result = cur.fetchall()
for i in result:
tree.insert('', 'end', values=i)
if var.get() == '作者':
sql = """ select * from book where author like %s """
t2 = ''
for i in range(len(t.get())):
t2 = t2 + t.get()[i] + '%'
params = '%' + t2
if cur.execute(sql, params) == 0:
showerror('查询失败', '请核实您输入的内容')
else:
x = tree.get_children()
for item in x:
tree.delete(item)
result = cur.fetchall()
for i in result:
tree.insert('', 'end', values=i)
if var.get() == '出版社':
sql = """ select * from book where publisher like %s """
t2 = ''
for i in range(len(t.get())):
t2 = t2 + t.get()[i] + '%'
params = '%' + t2
if cur.execute(sql, params) == 0:
showerror('查询失败', '请核实您输入的内容')
else:
x = tree.get_children()
for item in x:
tree.delete(item)
result = cur.fetchall()
for i