首页 > Python资料 博客日记
数据库期末作业,Python+sqlserver的学生成绩管理系统
2024-07-05 08:00:05Python资料围观117次
数据库期末要写一个程序连接本地数据库并实现一个功能,选了个学生成绩管理系统.
代码和数据库脚本奉上.
链接:百度网盘 请输入提取码 提取码:a95j
需求分析
用户登录,注册
学生能够查看自己成绩,修改自己密码
老师能够选择自己教授的课程进行成绩登记,以及通过学号和课程查找批改成绩,和修改密码
就是三个对于数据库的增删查改,第一波先设计数据库.
数据库设计
表结构
先设计用户登录账号密码表,就四个属性,账号(主键)密码编号和权限.另外应该把老师和学生分开放的,但是期末作业,怎么快怎么来.
CREATE TABLE [dbo].[systemusers](
[useid] [varchar](20) NOT NULL,
[usepass] [varchar](20) NOT NULL,
[sno] [varchar](20) NOT NULL,
[type] [int] NOT NULL,
CONSTRAINT [PK_user] PRIMARY KEY CLUSTERED
(
[useid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[systemusers] WITH CHECK ADD CONSTRAINT [FK_user_user] FOREIGN KEY([useid])
REFERENCES [dbo].[systemusers] ([useid])
GO
ALTER TABLE [dbo].[systemusers] CHECK CONSTRAINT [FK_user_user]
GO
那么然后就开始设计学生表,学生就要带学号(用户编号,主键),姓名,专业,科目,成绩.
CREATE TABLE [dbo].[Student](
[sno] [varchar](20) NOT NULL,
[sname] [varchar](20) NOT NULL,
[smajor] [varchar](20) NOT NULL,
[cname] [varchar](20) NOT NULL,
[igrade] [int] NULL,
CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED
(
[sno] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
随后是老师表,有老师编号,教学科目,教师编号.
CREATE TABLE [dbo].[Teacher](
[sno] [varchar](20) NOT NULL,
[sname] [varchar](20) NOT NULL,
[cname] [varchar](20) NOT NULL,
CONSTRAINT [PK_Teacher] PRIMARY KEY CLUSTERED
(
[sno] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
理论上来说应该再设计一个课程表和成绩表,以满足更高范式,但是偷偷懒这样也能用
目前数据库表就设计的差不多了,随便填几个数据就能用了.
数据库用户
数据库用户还是要创建一个,用ssms直接建立就好了,映射到我们需要的数据库上,叫什么都可以自己编
pyhton代码
登录页面
数据库连接
首先要连接上我们的数据库,这里使用python的mssql包来连接我们的sqlserver.
def sqlconnect():##数据库连接
server = "(local)"
user = "python"
password = "*******"
database = "MyDb"
global conn
conn= pymssql.connect(server, user, password, database,autocommit=True,charset='GBK')
global cursor
cursor= conn.cursor()
if not cursor:
tkinter.messagebox.showerror(title='错误',
message='数据库连接失败') # 信息错误弹窗,点击确定返回值为 ok
exit(0)
通过通过connect方法,获取数据库的连接对象conn,随后获取conn的游标对象,类似于字节流,对于数据库的操作都要通过cursor对象提交给数据库,随后数据库执行.
登录页面
页面的布局设计,使用tkinker进行布局,设计比较简陋,如有需要可以自己改.
先初始化Tkinker,随后通过布局,使页面居中,随后连接数据库,按键函数为登录和注册.
留了两个Label控件,用于获取输入.
root = Tk() #初始化Tk()
root.title('英才大学学生成绩管理系统')
root.resizable(0,0)
screenWidth = root.winfo_screenwidth() # 获取显示区域的宽度
screenHeight = root.winfo_screenheight() # 获取显示区域的高度
width = 300 # 设定窗口宽度
height = 200 # 设定窗口高度
left = (screenWidth - width) / 2
top = (screenHeight - height) / 2
# 宽度x高度+x偏移+y偏移
# 在设定宽度和高度的基础上指定窗口相对于屏幕左上角的偏移位置
root.geometry("%dx%d+%d+%d" % (width, height, left, top))
sqlconnect()
iser=1
useid=Entry(root)
usepass=Entry(root,show='*')
id=Label(root,text='账号')
pas=Label(root,text='密码')
id.place(x=40,y=0)
pas.place(x=40,y=20)
useid.pack()
usepass.pack()
login=Button(root,text='登录',command=lg,width=5)
login.place(x=80,y=50)
enroll=Button(root,text='注册',command=er,width=5)
enroll.place(x=160,y=50)
root.mainloop()
效果图就这样
登录功能
登录功能就挺简单了,用户提交账号密码后查询数据库,有数据就登录成功,无数据或者密码错误就提示不正确.
def lg():##登录
id=useid.get()
password=usepass.get()
selectsql="select * from systemusers where useid ='{}'".format(id)
cursor.execute(selectsql)
data=cursor.fetchall()
try:
if len(data)==1 and data[0][0]==id and str(data[0][1])==password:
mess1=Label(root,text='登录成功',font=('Arial', 12),width=15, height=2)
mess1.pack()
root.destroy()
root.quit()
root.mainloop()
system.work(data[0][2],data[0][3])
else:
tkinter.messagebox.showerror(title='错误',
message='账号或者密码错误') # 信息错误弹窗,点击确定返回值为 ok
except :
pass
else:
root.mainloop()
点击登录以后,Label获取输入,随后将输入格式化,提交查询,数据库返回一个元组结果,因为限定用户名为主键不能重复,所有返回元组只有一行,那我们根据表结构对数据进行比对即可,需要注意的是,数据库中返回类型和表中类型一直,表中char,varchar类型返回为字符类型结果,int类型也返回整形结果,部分需要转换.
如果比对正确,那么进入另一个页面.不正确就跳出错误弹窗
注册设计
注册设计也偷懒了,应该注册完然后补全信息的,但是我只留了注册的窗口,没有留在学生表中补全信息的功能,也就是说新注册的用户如果学生表中没有对应的学号数据的话是查不到成绩的.
def isregisterd():
id=useid1.get()
passw=usepass1.get()
no=sno1.get()
print(len(id))
if is_ok(id) and is_ok(passw) and is_ok(no) :
selectsql="select * from systemusers where sno ='{}'".format(no)
cursor.execute(selectsql)
data=cursor.fetchall()
try:
if no==data[0][2] :
tkinter.messagebox.showerror(title='错误',
message='已经注册过了') # 信息错误弹窗,点击确定返回值为 ok
except :
try:
selectsql="select * from systemusers where useid ='{}'".format(id)
cursor.execute(selectsql)
data=cursor.fetchall()
if id==data[0][0] :
tkinter.messagebox.showerror(title='错误',
message='账号重复') # 信息错误弹窗,点击确定返回值为 ok
except:
try:
selectsql="insert into systemusers values('{}','{}','{}',0)".format(id,passw,no)
cursor.execute(selectsql)
conn.commit()
display_rigmessage()
except :
display_errormessage()
else:
enr.destroy()
enr.mainloop()
else:
enr.mainloop()
else :
tkinter.messagebox.showerror(title='错误',
message='输入不合法') # 信息错误弹窗,点击确定返回值为 ok
enr.mainloop()
def er():##注册
global iser
if iser==1:
iser-=1
global enr
enr=Tk()
enr.resizable(0,0)
enr.title('注册')
screenWidth = enr.winfo_screenwidth() # 获取显示区域的宽度
screenHeight = enr.winfo_screenheight() # 获取显示区域的高度
width = 300 # 设定窗口宽度
height = 200 # 设定窗口高度
left = (screenWidth - width) / 2
top = (screenHeight - height) / 2
enr.geometry("%dx%d+%d+%d" % (width, height, left, top))
mess1=Label(enr,text='输入信息(仅限学生注册)',font=('Arial', 10),width=20, height=2)
mess2=Label(enr,text='账号')
mess3=Label(enr,text='密码')
mess4=Label(enr,text='学号')
catch=Button(enr,text='点击注册',command=isregisterd)
global useid1
useid1=Entry(enr)
global usepass1
usepass1=Entry(enr)
global sno1
sno1=Entry(enr)
useid1.place(x=80,y=30)
usepass1.place(x=80,y=50)
sno1.place(x=80,y=70)
mess1.place(x=70,y=0)
mess2.place(x=50,y=30)
mess3.place(x=50,y=50)
mess4.place(x=50,y=70)
catch.place(x=120,y=110)
enr.focus_force() #新窗口获得焦点
enr.mainloop()
else :
enr.focus_force() #新窗口获得焦点
isregisterd功能就和名字差不多,检测该用户,学号是否已经注册,对要注册的账号进行查询,如果重复就提示账号重复或者学号已注册.
er函数为组成页面,最开始使用一个全局变量,防止注册窗口多开,这里更应该检测er窗口是否存在的,但是使用全局变量简单一点,带来一个问题就是注册窗口叉掉以后不能再打开.
工作页面
root页面在登录成功后便销毁,防止工作页面多开.
学生和老师页面都是基于work类上的
class work(object):
def __init__(self,sno,type):
self.__sno=sno
self.__type=type
self.__newpass=None
self.__havepasschs=FALSE
server = "(local)"
user = "python"
password = "py031125"
database = "MyDb"
global conn
conn= pymssql.connect(server, user, password, database,autocommit=True,charset='utf8')
global cursor
cursor= conn.cursor()
if not cursor:
exit(0)
###完善自身信息############################################################################
if type==1:
cursor.execute("select sname from Teacher where sno ='{}'".format(sno))
name=cursor.fetchall()[0][0].encode('latin1').decode('gbk')
else :
try:
cursor.execute("select sname from Student where sno ='{}'".format(sno))
name=cursor.fetchall()[0][0].encode('latin1').decode('gbk')
except :
tkinter.messagebox.showerror(title='错误',
message='没有选课信息') # 信息错误弹窗,点击确定返回值为 ok
exit(0)
self.__name=name
cursor.execute("select usepass from systemusers where sno ='{}'".format(sno))
passw=cursor.fetchall()[0][0]
self.__passw=passw
global scr
scr= Tk()
scr.resizable(0,0)
global canvas
canvas= Canvas(scr, width=600,height=400,bd=0, highlightthickness=0)
scr.title('用户{}登录成功'.format(name))
screenWidth = scr.winfo_screenwidth() # 获取显示区域的宽度
screenHeight = scr.winfo_screenheight() # 获取显示区域的高度
width = 600 # 设定窗口宽度
height = 400 # 设定窗口高度
left = (screenWidth - width) / 2
top = (screenHeight - height) / 2
# 宽度x高度+x偏移+y偏移
# 在设定宽度和高度的基础上指定窗口相对于屏幕左上角的偏移位置
scr.geometry("%dx%d+%d+%d" % (width, height, left, top))
imgpath= 'beij.gif'
img = Image.open(imgpath)
global photo
photo = ImageTk.PhotoImage(img)
canvas.create_image(300, 200, image=photo)
canvas.pack()
if self.__type==0 :
self.stud()
scr.mainloop()################################ok
###################################################老师系统
1.#修改密码#
2.#登成绩
3.#查看成绩
elif self.__type==1:
self.teach()
scr.mainloop()
##sql="select type from systemusers where sno ='{}'".format(sno)
##print(sql)
##cursor.execute(sql)
上个页面传来的编号和权限参数,初始化work类,根据不同权限判断学生和老师,给不同功能按键
学生页面
效果如下,前端确实没怎么学,布局确实不太好看.
def stud(self):
text=Text(scr,width=400,height=70)
canvas.create_window(350, 85, width=400, height=70,window=text)
stubutton1=Button(scr,text='查看成绩',command=self.__showgrade,width=100,height=40)
stubutton2=Button(scr,text='修改密码',command=self.__changepass,width=100,height=40)
canvas.create_window(80, 70, width=100, height=40,window=stubutton1)
canvas.create_window(80, 120, width=100, height=40,window=stubutton2)
scr.mainloop()
通过两个按钮可以调用查看成绩和密码的函数
def __showgrade(self):
stutext=Text(scr,width=400,height=70)
canvas.create_window(350, 85, width=400, height=70,window=stutext)
cursor.execute("select * from Student where sno='{}'".format(self.__sno))
data=cursor.fetchall()
for i in range(len(data)):
stutext.insert(END,'\n学号:'+data[0][0]+'\n姓名:'+data[0][1].encode('latin1').decode('gbk')+'\n专业:'+data[0][2].encode('latin1').decode('gbk')+'\n科目:'+data[0][3].encode('latin1').decode('gbk')+'\n成绩:'+str(data[0][4]))
scr.mainloop()
def __changepass(self):
if self.__havepasschs == FALSE:
self.__havepasschs=TRUE
global passchs
passchs=Tk()
passchs.resizable(0,0)
passchs.title('密码修改')
screenWidth = passchs.winfo_screenwidth() # 获取显示区域的宽度
screenHeight = passchs.winfo_screenheight() # 获取显示区域的高度
width = 300 # 设定窗口宽度
height = 200 # 设定窗口高度
left = (screenWidth - width) / 2
top = (screenHeight - height) / 2
# 宽度x高度+x偏移+y偏移
# 在设定宽度和高度的基础上指定窗口相对于屏幕左上角的偏移位置
passchs.geometry("%dx%d+%d+%d" % (width, height, left, top))
mess1=Label(passchs,text='修改密码',font=('Arial', 10),width=20, height=2)
mess2=Label(passchs,text='原密码')
mess3=Label(passchs,text='新密码')
mess4=Label(passchs,text='确认新密码')
global oldpass
oldpass=Entry(passchs)
global newpass
newpass=Entry(passchs)
global realpass
realpass=Entry(passchs,show='*')
oldpass.place(x=80,y=30)
newpass.place(x=80,y=50)
realpass.place(x=80,y=70)
mess1.place(x=70,y=0)
mess2.place(x=30,y=30)
mess3.place(x=30,y=50)
mess4.place(x=10,y=70)
passchs.focus_force()
passchs.after(500,self.cpassget)
else :
passchs.focus_force()
def cpassget(self):
old=oldpass.get()
new=newpass.get()
real=realpass.get()
if is_ok(old) and is_ok(new) and is_ok(real) :
if old==self.__passw and new==real and real!=old:
self.__newpass=new
ts1=Label(passchs,text="密码正确",width=8,height=1,justify='left')
ts1.place(x=230,y=30)
ts2=Label(passchs,text="密码确认",width=8,height=1,justify='left')
ts2.place(x=230,y=70)
ts3=Label(passchs,text="密码不重复",width=8,height=1,justify='left')
ts3.place(x=230,y=50)
catch=Button(passchs,text='点击更改',command=self.__realchange)
catch.place(x=120,y=110)
else :
if old!=self.__passw :
ts1=Label(passchs,text="密码错误",width=8,height=1,justify='left')
ts1.place(x=230,y=30)
elif old==self.__passw :
ts1=Label(passchs,text="密码正确",width=8,height=1,justify='left')
ts1.place(x=230,y=30)
if new!=real :
ts2=Label(passchs,text="密码未确认",width=8,height=1,justify='left')
ts2.place(x=230,y=70)
elif new==real :
ts2=Label(passchs,text="密码确认",width=8,height=1,justify='left')
ts2.place(x=230,y=70)
if old!=new :
ts3=Label(passchs,text="密码不重复",width=8,height=1,justify='left')
ts3.place(x=230,y=50)
elif old==new :
ts3=Label(passchs,text="密码重复",width=8,height=1,justify='left')
ts3.place(x=230,y=50)
passchs.after(500,self.cpassget)
else :
passchs.after(500,self.cpassget)
这里通过递归页面延时来检测原密码,新密码和确认密码的合法性,最后,确认都合法以后给出修改按键.
老师页面
def teach(self):
tbutton1=Button(scr,text='编辑成绩',command=self.__grditgrade,width=100,height=40)
tbutton3=Button(scr,text='录入成绩',command=self.__setgrade,width=100,height=40)
tbutton2=Button(scr,text='修改密码',command=self.__changepass,width=100,height=40)
canvas.create_window(80, 70, width=100, height=40,window=tbutton1)
canvas.create_window(80, 120, width=100, height=40,window=tbutton3)
canvas.create_window(80, 170, width=100, height=40,window=tbutton2)
修改密码功能和学生的一样,不给出.
录入成绩
def __setgrade(self):
global sno
global ssub
global sgrade
global sbutton4
global smess4
global smess3
global smess2
global smess1
global front
global back
self.pos=1
self.__clean()
front=Button(scr,text='下一个',command=lambda :self.__choice(1,self.pos))
back=Button(scr,text="前一个",command=lambda :self.__choice(-1,self.pos))
sno=Entry(scr)
ssub=Entry(scr)
sgrade=Entry(scr)
smess1=Label(scr,text='学号:',bg='white')
smess3=Label(scr,text='成绩:',bg='white')
smess2=Label(scr,text='科目:',bg='white')
smess4=Label(scr,text='请先输入要录入的科目',bg='white')
sbutton4=Button(scr,text='点击查询',command=self.__beginset,width=80,height=40)
canvas.create_window(300, 70, width=120, height=20,window=ssub)
canvas.create_window(200, 70, width=30, height=20,window=smess2)
canvas.create_window(300, 30, width=180, height=40,window=smess4)
canvas.create_window(300, 220, width=80, height=40,window=sbutton4)
def __showeve(self):
global teach
teach=ssub.get()
smess2.destroy()
smess4.destroy()
sbutton4.destroy()
ssub.destroy()
canvas.create_window(200, 120, width=30, height=20,window=smess1)
canvas.create_window(200, 170, width=30, height=20,window=smess3)
canvas.create_window(300, 170, width=120, height=20,window=sgrade)
canvas.create_window(300, 120, width=120, height=20,window=sno)
sql="select * from Student where cname ='{}'".format(teach)
cursor.execute(sql)
global data
data=cursor.fetchall()
print(len(data))
sno.insert(0,data[0][0])
sgrade.insert(0,data[0][4])
canvas.create_window(250, 220, width=80, height=40,window=back)
canvas.create_window(350, 220, width=80, height=40,window=front)
scr.mainloop()
def __choice(self,f,pos):
set=int(sgrade.get())
if set >100 or set <0 :
tkinter.messagebox.showerror(title='错误',
message='不能这样打分11111') # 信息错误弹窗,点击确定返回值为 ok
else:
try:
sql="update Student set igrade ={} where sno='{}' and cname='{}'".format(sgrade.get(),sno.get(),teach)
cursor.execute(sql)
except :
tkinter.messagebox.showerror(title='错误',
message='出了点问题1111') # 信息错误弹窗,点击确定返回值为 ok
self.pos=pos+f
try:
sno.delete(0,END)
sgrade.delete(0,END)
sno.insert(0,data[pos][0])
sgrade.insert(0,data[pos][4])
except :
tkinter.messagebox.showerror(title='错误',
message='到头了') # 信息错误弹窗,点击确定返回值为 ok
self.teach()
def __beginset(self):
global teach
teach=ssub.get()
sbutton4.destroy()
flag=0
sql="select * from Teacher where sno ='{}'".format(self.__sno)
cursor.execute(sql)
for i in cursor.fetchall():
t=i[2].encode('latin1').decode('gbk')
if t==teach :
flag=1
if flag==1:
self.__showeve()
else :
tkinter.messagebox.showerror(title='错误',
message='您未教该科目') # 信息错误弹窗,点击确定返回值为 ok
首先通过要录入成绩的科目查询该老是是否教授该科目,如果是则显示学号以及成绩,然后进行顺序修改,通过按键进行录入学号成绩的移动,同时判断分数合法性.
修改成绩
def __grditgrade(self):
global gno
global gsub
global ggrade
global gmess1
global gmess2
global gmess3
global gmess4
global gbutton4
global gButton5
self.__clean()
gno=Entry(scr)
gsub=Entry(scr)
ggrade=Entry(scr)
gmess1=Label(scr,text='学号:',bg='white')
gmess2=Label(scr,text='科目:',bg='white')
gmess3=Label(scr,text='成绩:',bg='white')
gmess4=Label(scr,text='请先输入要编辑的学生学号科目',bg='white')
gbutton4=Button(scr,text='点击查询',command=self.__getinfstu,width=80,height=40)
gButton5=Button(scr,text="点击提交",command=self.__commitgrade,width=80,height=40)
canvas.create_window(200, 70, width=30, height=20,window=gmess1)
canvas.create_window(200, 120, width=30, height=20,window=gmess2)
canvas.create_window(200, 170, width=30, height=20,window=gmess3)
canvas.create_window(300, 30, width=180, height=40,window=gmess4)
canvas.create_window(300, 70, width=120, height=20,window=gno)
canvas.create_window(300, 120, width=120, height=20,window=gsub)
canvas.create_window(300, 170, width=120, height=20,window=ggrade)
canvas.create_window(300, 220, width=80, height=40,window=gbutton4)
def __getinfstu(self):
ggrade.delete(0,END)
sno=gno.get()
subname=gsub.get()
print(sno,subname)
if is_ok(sno) :
try:
cursor.execute("SELECT * FROM Student where sno='{}' and cname='{}'".format(sno,subname))
data=cursor.fetchall()
print(data)
ggrade.insert(0,str(data[0][4]))
canvas.create_window(300, 270, width=80, height=40,window=gButton5)
except:
tkinter.messagebox.showerror(title='错误',
message='好像出了点问题,要不再试试?') # 信息错误弹窗,点击确定返回值为 ok
else:
tkinter.messagebox.showerror(title='错误',
message='错误输入') # 信息错误弹窗,点击确定返回值为 ok
def __commitgrade(self):
newgrade=int(ggrade.get())
if newgrade>100 or newgrade<0 :
tkinter.messagebox.showwarning(title='???',
message='分不是这样打的') # 信息错误弹窗,点击确定返回值为 ok
else :
try:
sql="update Student set igrade ={} where sno='{}' and cname='{}'".format(ggrade.get(),gno.get(),gsub.get())
print(sql)
cursor.execute(sql)
tkinter.messagebox.showinfo(title='成功',
message='更改成功')
self.__grditgrade()
except :
tkinter.messagebox.showerror(title='错误',
message='出了点问题') # 信息错误弹窗,点击确定返回值为 ok
首先通过学生学号科目查询,如果查询到就可以点击提交修改,没有则返回错误弹窗
总结
属于是数据库大作业最后几天赶工,以前也没试过带数据库的作业,最后写出来这个,可能写的不是太好但是作为学习的一部分也发出来
新链接已上传
链接:https://pan.baidu.com/s/1XnydmnCMo3JnZqh1ed5YaQ
提取码:a95j
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Anaconda版本和Python版本对应关系(持续更新...)
- Python与PyTorch的版本对应
- Windows上安装 Python 环境并配置环境变量 (超详细教程)
- Python pyinstaller打包exe最完整教程