本项目的最终结果会以网页形式呈现,读者只需要完成整个系统中关于MongoDB 操作这部分代码的开发即可。
完成以后,将会得到一个人员信息管理网页,如图所示。在页面的末尾可以看到用于新增数据的“添加人员”按钮。通过这个网页,可以查看当前的所有人员信息,可以增加、修改、删除人员信息。
image.png
1.添加信息
(1)可以单击“添加人员”按钮,打开“添加信息”对话框。
(2)在“添加信息”对话框中输入相应的信息,则信息会被添加到MongoDB 中,同时也出现在网页中,如图所示:
image.png
image.png
2.编辑信息
(1)单击界面每条信息后面的“编辑”按钮,会打开“编辑信息”对话框。“编辑信息”对话框中已经自动填入了当前人员的信息,除“工号”与“年龄”外,其他信息都可以修改。其中,年龄会通过修改“出生年月日”而自动修改。
image.png
2)修改一项或多项以后,单击“更新”按钮更新本条数据。
3.删除信息
单击每一条信息后面的“删除”按钮,则可以将当前信息删除,如图所示。
image.png
工号一旦被自动生成就固定不变,不会因为删除某个人的信息而导致后面人的工号发生改变。
2 准备工作
2.1 拉取项目
代码语言:javascript复制git clone https://github.com/sunsharing-note/MonogoDB.git
2.1 了解文件结构
项目的初始文件结构如下:
image.png
其中主要文件说明如下:
● Pipfile与Pipfile.lock:Pipenv配置运行环境的文件,用来记录项目所需要的第三方库
● answer文件夹下面的DataBaseManager.py:本项目的参考答案。读者在自己完成项目以后可以将自己的代码与参考代码进行对比
● bin文件夹下的generate_data.py:用来向数据库中插入初始数据
● main.py、static、templates、util 文件夹:其中是本项目网站的后台和前台相关的代码,读者不需要关心
2.2 搭建项目运行环境
在Python开发中,常使用pip来安装不同的第三方库。如果把所有第三方库全部安装到系统的Python环境中,则可能会导致系统环境不稳定。而且,如果两个不同的项目依赖于同一个第三方库的不同版本,那么处理冲突也非常麻烦。
virtualenv 是一个创建 Python 虚拟环境的工具,它可以为每一个Python 项目创建不同的Python虚拟环境,各个环境之间互相隔离,从根本上解决了第三方库冲突的问题。
由于virtualenv命令的参数众多而且操作复杂,不利于初学者直接使用,因此需要使用一个更加简单的工具来管理virtualenv,本文使用Pipenv来实现这一目的。
Pipenv会自动调用virtualenv创建虚拟环境,并在虚拟环境中安装第三方库,所以使用Pipenv会大大简化Python项目的环境搭建工作。
1.安装Pipenv
安装Pipenv需要在Linux/macOS的终端或者Windows的DOS窗口中执行pip命令:
代码语言:javascript复制python3 -m pip install pipenv
2.创建本项目所需要的Python环境
(1)安装完成后,通过命令行或者终端进入本项目所在的文件夹(例如:E:文档资料SourceCodeofMongoRedis-masterproject_1)。
(2)进入后,执行如下命令就能创建本项目所需要的Python环境:pipenv install
(3)运行命令以后,Pipenv会自动读取Pipfile和Pipfile.lock这两个文件,从而知道需要安装哪些第三方库的什么版本。运行效果如图所示:
image.png
3.进入虚拟环境
(1)安装完成以后,根据提示执行以下命令:
pipenv shell
(2)自动进入专门为本项目定制的虚拟环境,如图所示,方框框住的部分是本项目虚拟环境的名字,提示当前终端处于虚拟环境中。
image.png
提示:虚拟环境提示有多种显示形式,这取决于终端的显示设置。所以,可能大家看到的与图中所示的位置或者格式略有差异。
此时,如果使用的是“python3×××.py”命令,则调用的是虚拟环境中的Python 3,不会受系统环境的影响。在本项目的开发过程中,请全程不要关闭当前这个终端窗口,因为本项目是前台运行,涉及的所有命令都需要在这个窗口中执行。
提示:如果不小心关闭了这个终端窗口,则需要执行命令重启虚拟环境。 如在macOS/Linux中,则需要执行以下两条命令进入项目文件夹并启动虚拟环境: cd ~/mongoredis/project_1 pipenv shell 如在Windows中,则需要执行以下两条命令进入项目文件夹并启动虚拟环境: cd C:project_1 pipenv shell 关于Pipenv的详细使用说明,读者可以参考https://github.com/pypa/pipenv。
2.3 启动项目
设置好虚拟环境后,就可以启动网站了
1.Linux/macOS系统对于Linux/macOS系统,在虚拟环境中执行以下命令:
代码语言:javascript复制export FLASK_APP=main.py
flask run
其中,第1行代码添加环境变量,变量名为“FLASK_APP”,值为“main.py”;第2行代码通过flask启动网站。
2.Windows系统
对于Windows系统,按以下步骤来启动项目。(本文以windows系统操作为例)
(1)在DOS窗口中以下执行命令:
代码语言:javascript复制set FLASK_APP=main.py
flask run
(2)运行效果如图所示:
image.png
(3)打开浏览器,输入网址:http://127.0.0.1:5000,可以看到如图所示的页面:
image.png
此时,即使没有启动MongoDB,也可以看到页面上有三条测试数据,没法进行操作,仅作测试展示
● 单击“添加人员”按钮,会弹出“添加信息”对话框,但是添加的任何信息都不会出现在页面上,也不会被写入数据库中。
● 单击“编辑”按钮也能打开编辑信息对话框,但是对信息的任何修改都不会生效。
● 单击“删除”按钮无法删除当前的三条测试数据。
打开your_code_here文件夹下面的DataBaseManager.py文件,其中的代码如图所示:
image.png
本项目实现 DataBaseManager 类下面的不同方法,从而使人员管理系统可以正常工作。本项目中所有需要读者修改的地方都在代码的注释中进行了提示。
3 项目开发过程
3.1 生成初始数据
在项目的bin文件夹下有一个generate_data.py文件,文件中的代码如图所示:
image.png
在本地启动 MongoDB,运行这个文件中的代码,则会在本地 MongoDB中创建一个名为“chapter_4”的数据库,并在其中创建一个名为“people_info”的集合。初始状态会向集合中插入19条数据,如图所示:
image.png
提示:“初始数据生成程序生成”的人名、年龄和地址都是随机拼接的,因此每一位读者生成的初始数据都是不一样的。但可以确定的是,人名“小四”和“小六”中间没有“小五”
3.1 实现“查询数据”功能
查询数据对应了DataBaseManager类里面的query_info()方法。在初始状态下,这个方法返回的是三条假数据
image.png
方框框住的代码为:
代码语言:javascript复制 def query_info(self):
"""
你需要在这里实现这个方法,
查询集合people_info并返回所有"deleted"字段为0的数据。
注意返回的信息需要去掉_id
"""
return [
{'id': 1, 'name': '测试数据', 'age': 18, 'birthday': '2000-01-02',
'origin_home': '测试数据', 'current_home': '测试数据'},
{'id': 2, 'name': '测试数据', 'age': 18, 'birthday': '2000-01-02',
'origin_home': '测试数据', 'current_home': '测试数据'},
{'id': 3, 'name': '测试数据', 'age': 18, 'birthday': '2000-01-02',
'origin_home': '测试数据', 'current_home': '测试数据'}]
现在的目标是,用 query_info()方法查询 MongoDB,并以列表的形式返回集合里面的所有数据。由于无论是查询、增加、修改,还是删除数据,都会涉及数据库连接,因此,可以先在__init__()方法中创建数据库连接对象,这样在后面的其他方法中都能够直接使用,不需要多次初始化数据库连接
1.创建数据库连接对象
修改__init__()方法中的代码,连接数据库并定位到people_info集合,构造函数
代码语言:javascript复制 def __init__(self):
"""
你需要在这里初始化MongoDB的连接,连上本地MongoDB,库名为chapter_4,集合名为people_info
"""
client = MongoClient()
database = client.chapter_4
self.handler = database.people_info
其中,主要代码说明如下:
● 第5行代码:创建MongoDB的连接
● 第6行代码:指定使用“chapter_4”数据库
● 第7行代码:指定使用“people_info”集合
2. 查询集合中所有“deleted”字段为0的信息
接下来完成query_info()方法,查询集合中所有“deleted”字段为0的信息
代码语言:javascript复制 def query_info(self):
"""
你需要在这里实现这个方法,
查询集合people_info并返回所有"deleted"字段为0的数据
注意返回的信息需要去掉_id
"""
info_list = list(self.handler.find({'deleted': 0}, {'_id': 0}))
return info_list
其中,主要代码说明如下:
● 第8行代码:“self.handler.find({'deleted': 0},{'_id': 0})”查询到所有deleted字段为0的数据,去掉ObjectId以后返回。再使用Python的list()方法把pymongo返回的对象转换为包含字典的列表。
● 第9行代码:将转换成的包含字典的列表返回。
在虚拟环境中,使用“Ctrl C”组合键关闭网站程序,然后再重新启动。
刷新浏览器后可以看到,数据库中的信息已经成功显示在网页中了。
img
3.2 实现“添加数据”功能
添加数据的逻辑如下:
- (1)如果people_info集合中没有数据,那么添加的人员工号为“1”
- (2)如果people_info中有数据,那么新的人员工号是“已有最大工号加1”
- (3)插入数据
1. 查询已有工号
首先需要查询people_info集合,寻找当前最大的工号。根据前面介绍的添加逻辑中的(1)和(2)两点,完善_query_last_id()方法
代码语言:javascript复制 def _query_last_id(self):
"""
你需要实现这个方法,查询当前已有数据里面最新的id是多少
返回一个数字,如果集合里面至少有一条数据,那么就返回最新数据的id,
如果集合里面没有数据,那么就返回0
提示:id不重复,每次加1
:return: 最新ID
"""
last_info = self.handler.find({}, {'_id': 0, 'id': 1}).sort('id', -1).limit(1)
return last_info[0]['id'] if last_info else 0
其中,主要代码说明如下。
● 第10行代码:首先查询people_info集合,以“id”字段倒序排列,只取倒序排列以后的第1条数据,即id最大的那一条数据。
● 第11行代码:如果people_info不为空,那么if last_info判断语句会执行if左边的语句,并且变量last_info可以像列表一样读取下标为0的元素,再读取这个元素的id,这就是当前最大的id了,读取以后返回。如果people_info集合是空的,那么if last_info判断语句会执行else右边的语句,返回整数0。
2 添加新数据
add_info()方法首先调用_query_last_id()方法获得当前最大的id,然后把这个id加1作为新的id。再将新的id放到参数需要插入的字典“para_dict”中并插入数据库中。
3 测试添加数据
添加好数据之后,会自动添加到最后,如图所示:
image.png
3.3 实现“更新数据”功能
1.实现数据更新逻辑
更新数据的逻辑非常简单,根据工号id找到MongoDB中对应的记录并更新即可。涉及的代码如下:
代码语言:javascript复制 def update_info(self, people_id, para_dict):
"""
你需要实现这个方法。这个方法用来更新人员信息。
更新信息是根据people_id来查找的,因此people_id是必需的。
:param people_id: 人员id,数字
:param para_dict: 格式为{'name': 'xxx', 'age': 12, 'birthday': '2000-01-01', 'origin_home': 'xxx', 'current_home': 'yyy'}
:return: True或者False
"""
try:
y = self.handler.update_one({'id': people_id}, {'$set': para_dict})
print(y)
except Exception as e:
print('更新数据错误,报错信息如下:{}'.format(e))
return False
return True
其中,主要代码说明如下。
● 第10行代码:根据id更新数据。para_dict的格式与添加新数据时的相同。
● 第11行代码:打印更新返回的对象。这是一行不重要的语句,可以省略。
● 第9行与第12行,使用try...except Exception把更新代码“包”起来,这样遇到更新数据出错时就会把错误信息打印出来,并返回False。
3.4 实现“删除数据”功能
1.实现删除数据的逻辑
为了防止数据的误删除,使用“假删除”是一个简单有效的方法。在查询数据时,用到的查询条件为“deleted字段为0”,那么只要把deleted字段改为非0就可以让数据查不出来,也就变相实现了删除的功能。因此,删除数据的本质仍然是更新数据
代码语言:javascript复制 def del_info(self, people_id):
"""
你需要实现这个方法。请注意,此处需要使用"假删除",
把删除操作写为更新"deleted"字段的值为1
:param people_id: 人员id
:return: True或者False
"""
return self.update_info(people_id, {'deleted': 1})
其中,第8行代码调用了update_info()这个方法,传入了将要被删除的工号id。与前面更新用户信息不同,删除信息时只需要更新“deleted”字段,把该字段的值设为1。这样在数据查询阶段就无法查出数据了
2. 删除数据测试
l例如删除工号为“13”人员的信息,在网页上点击这一行数据后面的删除按钮,则在网页上已经不能看到工号为“12”的这个人员的信息了。在数据库中,这个人员的deleted字段变成了1
image.png
image.png
提示:目前互联网上很多声称能够注销并删除账号的网站,几乎都是使用的假删除。虽然用户“注销”以后确实无法登录,但网站并不会删除用户的信息,只是通过修改数据库中的某个字段,让这个账号看起来像是被删除了而已。
小结
使用一个人员管理网站的实例来帮助读者巩固 MongoDB 的基本操作。整个过程使用基于 Python 的网络框架 Flask 来实现。读者只需要修改 your_code_here 文件夹下面的DataBaseManager.py中的相应方法,就可以用图形化的方式直观地看到代码的运行结果,希望大家能够通过本项目的学习,能够明白如何使用python来进行MongoDB的学习,在日常工作中可以使用python来进行数据的入库等操作,方便数据的分析和管理。