[关闭]
@shaobaobaoer 2020-03-23T15:12:00.000000Z 字数 7536 阅读 627

数据库原理期末个人报告

数据库原理


Python 开发环境与常用工具介绍

连接 SQL Server方法

SQL Server 设置外部链接

参考了网上的方法,过程如下

1.设置SQLSERVER混合模式(SQL Server 身份验证和Windows 身份验证)

2.启用SQL服务TCP/IP,启用协议与IP地址

3.启用SQL服务SQLSERVER Browser /Sql Server(实例名)

4.CMD命令输入:netstat -a 如果找到有“0.0.0.0:1433”,就说明SqlServer在监听了

5.防火墙应用通过window防火墙进行通信,添加应用

  1. C:\Program Files\Microsoft SQLServer\MSSQL10.MSSQLSERVER\MSSQL\Binn\sqlservr.exe

6.防火墙-高级设置,添加入站规则1433端口

利用Python链接SQL Server

使用python连接的方法很简单。利用pymssql库就可以轻松连接,方法如下

  1. self.conn = pymssql.connect(MSSQL_HOST, MSSQL_USER,
  2. MSSQL_PASSWORD, MSSQL_DATABASE)

其中包括了一些超参数,比如地址,用户,密码和DB名字,我的设置如下(我的数据库在虚拟机里,所以是192.168的IP地址)

  1. MSSQL_HOST = "192.168.25.134"
  2. MSSQL_USER = "shaobao"
  3. MSSQL_PASSWORD = "toor"
  4. MSSQL_DATABASE = "newdb"

学生选课成绩管理系统开发过程说明

项目分类和应用

面对这样一个问题,我们最主要的任务是分清楚我们需要哪些界面。其实详细划分一下的话,也不是很困难。

我主要用的是WXpython来建立的GUI程序。根据题目要求,我需要很多的子窗口以及一个主窗口,我命名这些窗口分别如下所示。父子类别用\t来分隔开

  1. Index.py
  2. 主界面
  3. MessageDialog.py
  4. 辅助提示框
  5. StudentLogin.py
  6. 登陆界面
  7. StudentChooseClass.py
  8. 学生选课界面
  9. StudentScoreList.py
  10. 学生成绩界面
  11. ScoreManageMent.py
  12. 管理界面
  13. ScoreAnalyze.py
  14. 成绩分析界面
  15. ManageClassDetail.py
  16. 课程管理界面
  17. ClassDetailInputDialog.py
  18. 添加课程界面
  19. ManageStudentDetail.py
  20. 学生管理界面
  21. StudentDetailInputDialog.py
  22. 添加学生信息界面

此外,我们将在最外层的Mian_frame中绑定这些页面并添加事件。大致的代码如下所示

  1. def OnInit(self):
  2. # Init All frames
  3. self.Index = Index(parent=None)
  4. self.ScoreManageMent = ScoreManageMent(parent=None)
  5. self.ScoreManageMent.col2teacher_dict = self.DBA.get_c()
  6. self.ScoreManageMent.m_choice_show_selectable_columnsChoices \
  7. = list(self.ScoreManageMent.col2teacher_dict.keys())
  8. self.ScoreManageMent.m_choice_show_selectable_columns.SetItems(
  9. self.ScoreManageMent.m_choice_show_selectable_columnsChoices
  10. )
  11. self.StudentChooseClass = StudentChooseClass(parent=None)
  12. self.StudentLogin = StudentLogin(parent=None)
  13. self.StudentScoreList = StudentScoreList(parent=None)
  14. self.ScoreAnalyze = ScoreAnalyze(parent=None)
  15. self.ManageClassDetail = ManageClassDetail(parent=None)
  16. self.ManageStudentDetail = ManageStudentDetail(parent=None)
  17. # Init Router
  18. self.__bind_router()
  19. self.__bind_event()
  20. # Show Index
  21. self.Index.Show(show=True)
  22. return True

绑定路由与添加事件

问题描述:需要保持当前打开的窗体为一个

问题分析:添加路由函数

很显然,原生的WXpython并没有路由方法,甚至Wxpython对于单界面的GUI有着更好的支持。要保持当前打开的窗体为一个,需要定义一些函数,比如某个窗体关闭,某个窗体会打开。对此,我们需要自定义一些事件。我参照了网络后端架构的后端的路由函数。将一些事件固定得绑定到这个函数,就可以实现这样子的功能。具体的方法如下所示

  1. def OnRouter_change(self, event, value='Index'):
  2. self.__current_active_frame = value
  3. if self.__current_active_frame == "Index":
  4. self.Index.Show()
  5. self.StudentLogin.Hide()
  6. self.StudentChooseClass.Hide()
  7. self.StudentScoreList.Hide()
  8. self.ScoreManageMent.Hide()
  9. self.SetTopWindow(self.Index)
  10. elif self.__current_active_frame == "StudentLogin":
  11. self.Index.Hide()
  12. self.StudentLogin.Show()
  13. self.StudentChooseClass.Hide()
  14. self.StudentScoreList.Hide()
  15. self.ScoreManageMent.Hide()
  16. self.SetTopWindow(self.StudentLogin)
  17. ...

很显然,我将会判断传入OnRouter_change事件的传入值。通过传入值来判断,让哪些页面Hide。让哪一个页面Show。

遇上的难题:如何给wxpython传值

然而,在wxpython的原声实现中,并不支持给事件传值。因为事件绑定的是一个函数名而传参。形如这样的形式

  1. self.StudentChooseClass.drop_class_button.Bind(wx.EVT_BUTTON,self.OnDropSelectedClass_StudentChooseClass)

问题解决:lambda方法

最后,我在wxpython advancer 文档中查阅到,如果需要给事件传递参数,需要用到lambda方法,并且附上默认得event参数。
解决方案如下

  1. self.Bind(wx.EVT_BUTTON,
  2. lambda event: self.OnRouter_change(event, 'StudentLogin'),
  3. self.Index.m_button_Index2StudentLogin)

问题3 学生成绩分析页面

问题描述:如何将直方图嵌入到wxpython中

问题分析:利用 matplotlib

在这个页面中。我们需要将每门课的成绩输出一个平均分,做成一个纵向的直方图。我想到我能够利用matplotlib库的作图工具来完成这个操作。生成一个平均分的纵向直方图诚然不难。原生的代码如下

  1. label_list, data_list = self.DBA.get_avg_s_group_by_class()
  2. width = 0.4
  3. ind = np.linspace(1.5, 7.5, data_list.__len__())
  4. for i in range(data_list.__len__()):
  5. self.axes.barh(ind[i] - width / 2, data_list[i],
  6. width,
  7. color=self.color_list[i % self.color_list.__len__()],
  8. label=data_list[i])
  9. self.axes.set_yticks(ind)
  10. self.axes.set_yticklabels(label_list)
  11. self.axes.set_ylabel('课程名称')
  12. self.axes.set_xlabel('平均成绩')
  13. self.axes.set_title('成绩分布')
  14. self.axes.legend()

遇上的难题1:如何把图片放到GUI界面?

然而,图片是图片,GUI是GUI。如果把图片保存到本地,用GUI再次读取,也是个不错的方法,但是这样一点也不geek。应该如何把连个结合起来呢?

问题解决1: 利用WXAgg后端

实际上,matplotlib已经为我们想到了方法,其实matplotlib可以用一个后端,叫做WXAgg。该后端完美支持了全平台的wxGUI框架。python自然也不例外。只需要在包引入上动些脑经就可以了

  1. matplotlib.use('WXAgg')
  2. from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
  3. from matplotlib.figure import Figure
  4. import matplotlib.pyplot as plt
  5. class ScoreAnalyze(wx.Frame):
  6. def __init__(self, parent):
  7. ...
  8. self.figure = Figure()
  9. self.axes = self.figure.add_subplot(111)

这样,axes就会调用我们生成图像的句柄,将图像返回到GUI界面中并打应出来。

遇上的难题2:中文乱码

实际上,在matplotlib中对于非西文字体的支持非常差,动不动就乱码。实际上这也是在matplotlib库利用中非常头大的问题。用英文自然也可以,但是这样就无法达到老师的要求了。

问题解决2:确认plt的字体文件

比较简单的方法,是定义plt的字体。将字体设置为SimHei来让中文不乱码。需要每次引用的时候都写一遍,虽然绝非一劳永逸,但是也能缓解这样的问题。

  1. plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
  2. plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

还有直接修改源文件的方法,再次不多赘述。

最终图片就能顺利打印出来了
TIM图片20190307220350.png-38.4kB

数据管理页面

问题描述:如何通过表格更改实现DML语句

DML语句,包括了增删改查。查自然是没什么问题。重要的就是增删改,毕竟wxpython不是PB。前端的修改必须通过SQL语句返回后端去,如何实现这些方法呢?
TIM图片20190307220611.png-75.3kB

问题分析:分开处理

行吧,毕竟我们没有PB这么好用的数据窗口,那就多加几个键分开处理。因此,我增加了新增,保存,删除和退出键。把增删改给分开来

遇上的难题1 :删除键

删除键,就是点了删除该咋办呢?如何生成SQL语句呢?

问题解决1 :通过弹出框输入主键删除

讲道理,应该是需要做一个弹出框,让用户输入主键后删除,并且设置为NOT NULL的主键,不应该允许用户在插入的时候将其清空。对此,我们需要用到之前弹出框文件中自定义的一种弹出框。

对此我新建立了一个临时的弹出框,让用户输入主键,随后返回给DB类,让它生成delete语句

  1. def delete_action(self, event):
  2. dlgtext = wx.TextEntryDialog(
  3. self, '请输入删除的课程号号',
  4. '提示信息', 'C1')
  5. # dlgtext.SetValue("Python is the best!")
  6. if dlgtext.ShowModal() == wx.ID_OK:
  7. SNO = dlgtext.GetValue()
  8. self.DBA.manage_c_delete_data(SNO)
  9. dlgtext.Destroy()
  10. self.OnRefresh_Data()
  11. def manage_c_delete_data(self, CNO):
  12. cursor = self.conn.cursor(as_dict=True)
  13. cursor.execute("DELETE FROM C WHERE CNO = '{}'".format(CNO))

这样就能做到删除了

遇上的难题2:新增键

新增也是一个头大的东西,如果让用户在前端的表格中输入东西并返回语句的话,做一些数据的检查很困难。

问题解决2

对此,我需要自定义一个弹出框,让用户来输入东西。
就像这个样子
TIM截图20190307221703.png-18.8kB

由于窗体代码非常复杂,所以不贴了。具体会在后文的github下载链接中查看。

点击提交后,会出发这样一个函数,主要就是检查主键是否为空。MessageDialog_CANCEL是我们编写的一个通用提示框类。

  1. def GetInputValue(self):
  2. if self.m_textCtrl_SNO.GetValue() == "":
  3. MessageDialog_CANCEL("SNO 不可为空", "错误信息")
  4. return [
  5. self.m_textCtrl_SNO.GetValue(),
  6. self.m_textCtrl_SNAME.GetValue(),
  7. self.m_textCtrl_SEX.GetValue(),
  8. self.m_textCtrl_AGE.GetValue(),
  9. self.m_textCtrl_SDEPT.GetValue(),
  10. str(__import__("random").randint(80, 760)),
  11. self.m_textCtrl_LOGN.GetValue(),
  12. self.m_textCtrl_PSWD.GetValue()
  13. ]

在审核通过后,会通过一个句柄传递给DBA的数据库控制类。生成INSERT 语句并执行。

  1. def insert_action(self, event):
  2. dlgtext = StudentDetailInputDialog(None)
  3. if dlgtext.ShowModal() == wx.ID_OK:
  4. insert_data = dlgtext.GetInputValue()
  5. if insert_data[0] == " ":
  6. return False
  7. else:
  8. self.DBA.manage_s_insert_data(insert_data)
  9. self.OnRefresh_Data()

遇上的难题3:改键

修改数据可能是最为困难的了。需要判断哪些列被修改,并返回SQL语句

问题解决3

这个和之前在修改成绩的时候的方法很类似,修改成绩也是这么实现的。

  1. def update_action(self, event):
  2. if self.lock_for_grid == False:
  3. self.lock_for_grid = True
  4. self.m_button_insert.Disable()
  5. self.m_button_delete.Disable()
  6. self.m_button_exit.Disable()
  7. self.m_button_update.SetLabel("提交")
  8. self.m_grid_manage_student_detail.EnableEditing(True)
  9. self.renew_raw_list_value()
  10. else:
  11. self.DBA.manage_s_update_data(numpy.argwhere(changed_list!=raw_list),self.column_value)
  12. self.m_grid_manage_student_detail.EnableEditing(False)
  13. self.m_button_update.SetLabel("保存")
  14. self.m_button_insert.Enable()
  15. self.m_button_delete.Enable()
  16. self.m_button_exit.Enable()
  17. self.lock_for_grid = False
  18. self.OnRefresh_Data()

程序运行部分结果截屏

此处输入图片的描述

代码地址

https://github.com/ninthDevilHAUNSTER/DB_PB_homework

认识;体会;建议;意见

这次PB实验,实际上我是用的WXPYTHON做的。我学会了如何用可视化工具来编写自己的GUI窗口,而不是之前那样子直接开局一个记事本,代码全靠敲。尽管用GUI界面建立了窗口,但是还是要写很多的事件绑定代码。其中,我写了主窗体以及路由函数,小组里余下三位同学写了登陆,选课和成绩分布。我写了管理界面,并整合了他们的代码。将小组的代码绑定路由并修改了一番。

获益还是很多的,比如说我们组加起来的总代码量超过了2229行。

  1. github.com/AlDanial/cloc v 1.80 T=0.50 s (74.0 files/s, 11786.0 lines/s)
  2. -------------------------------------------------------------------------------
  3. Language files blank comment code
  4. -------------------------------------------------------------------------------
  5. Python 28 771 377 2229

再比如说我们一共写了10个主窗体...嗯没错,GUI都是我画的。

最后,我觉得这个实验还是很有趣的,毕竟全程用python写就很有挑战性。实际上在这个功能上,我本来想用sqlmap的页面相似度算法,但是发现自己需要判断非常多的东西。最终还是放弃了异或运算。转向了numpy的怀抱,发现这个东西非常好用。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注