我们采用flask来开发该系统,Flask 是一个使用 Python 编写的轻量级 Web 应用程序框架。该系统有一下功能:
- 管理部门将能够登记疫苗接受者。
- 管理人员将能够更新和删除收件人的详细信息。
- 管理人员将能够查看在该疫苗接种中心登记的所有疫苗接受者。
1.安装环境
- 安装 Python 3.x
- 安装flask
$ pip install Flask
3.设置虚拟环境
Python 3 内置了用于创建虚拟环境的 venv 模块。在windows下:
$ py -3 -m venv venv
4.安装mysql。
2.设置数据库
让我们来创建一个数据库来存储接种人的信息
C:\Users\utsav>mysqlsh MYSQL JS>\sql MYSQL SQL>\connect root@localhost:3306 Creating a session to 'root@localhost:3306' Please provide the password for 'root@localhost:3306': ********* MySQL [localhost ssl] SQL>CREATE DATABASE vaccination_drive; MySQL [localhost ssl] SQL>CREATE USER 'doc'@'localhost' IDENTIFIED BY 'doc'; MySQL [localhost ssl] SQL>GRANT ALL PRIVILEGES ON vaccination_drive.* TO 'doc'@'localhost'; MySQL [localhost ssl] SQL>\exit
通过上面的操作,我们创建了一个名为vacination_drive的数据库,一个名为doc且具有密码doc的用户,并已授予doc所有数据库权限。
我们现在必须在数据库中创建一个名为疫苗接种的表
C:\Users\utsav>mysqlsh MYSQL JS>\sql MYSQL SQL>\connect doc@localhost:3306/vaccination_drive MYSQL SQL>create table vaccination ->( ->reference_number int primary key auto_increment, ->name char(20) not null, ->mobile_number char(12) not null, ->aadhar_card_number char(20) not null, ->vaccine_name char(20) not null ->);
现在,我们已经为我们的 Web 应用程序设计好了数据库。
3.设置项目的虚拟环境
接下来,为我们的Web 应用系统设置和激活虚拟环境。
C:> md vaccinecrud C:> cd vaccinecrud C:\vaccinecrud> virutalenv vaccinecrudenv C:\vaccinecrud> vaccinecrudenv\Scripts\activate
我们已经完全建立了虚拟环境,现在我们必须为这个虚拟环境安装flask和mysql-connector。
(vaccinecrudenv) C:\vaccinecrud>pip install flask (vaccinecrudenv) C:\vaccinecrud>pip install mysql-connector-python
4.项目目录结构
|------ vaccinecrud |-------templates | |-------base.html | |------- index.html | |------- register.html | |------- update.html | |------- message.html | |------- error.html | |-------vaccinecurd.py |-------vaccinecrudenv
vacuumcrud.py将是我们的后端 Python 脚本,我们将在此文件中编写所有后端 Python 代码。在vaccinecrud文件夹中有2个目录,即vaccinecrudenv和templates。目录vacuumcrudenv 包含与虚拟环境相关的脚本。模板文件夹将包含将由 jinja 2 模板引擎呈现的所有 HTML 模板文件。文件 base.html是公用文件,其他模板将集成该文件。
5.设计 Web 应用程序
设计后台代码是最有意义的一步。将以下导入语句添加到文件vacuumcrud.py 中。
from flask import Flask,render_template,request from mysql.connector import connect
我们已经导入了 Flask、render_template 和来自模块 flask 的请求并从 mysql.connector 进行连接 由于我们的 Web 应用程序需要与数据库频繁连接,因此,我们将创建一个名为 get_db_connection() 的函数,该函数将返回一个 MySQLConnection 类型的对象。
def get_db_connection() : mysqlConnection=connect(host="localhost",port=3306,database="vaccination_drive",user="doc",password="doc") return mysqlConnection
然后,我们将创建一个 Flask 类的对象,并将主模块的名称传递给它。
app=Flask(__name__)
vaccine_dict={} @app.before_first_request def populate_ds() : conn=get_db_connection() cursor=conn.cursor() rows=cursor.execute("select * from vaccination") rows=cursor.fetchall() if rows==None : return for row in rows: info={} info["reference_number"]=row[0] info["name"]=row[1] info["mobile_number"]=row[2] info["aadhar_card_number"]=row[3] info["vaccine_name"]=row[4] vaccine_dict[row[0]]=info conn.close()
populate_ds() 方法是用 before_first_request 装饰器定义的,所以flask框架会在第一次向服务器请求之前执行这个方法,并且这个方法会将查到的数据填充到vaccine_dict。
现在,由于我们采用了 jinja 2模板引擎,所以可以使用它的 html继承功能,因此我们其他的页面都将继承base.html页面。
<!--------base.html---------> <!DOCTYPE HTML> <html lang="en"> <head> <meta charset='utf-8'> <title>Vaccination Drive</title> </head> <style> {% block style %}{% endblock %} #tb,th,td{ border: 1px solid black; border-collapse : collapse; } th,td{ padding : 7px; } </style> <body> <center> <h1>Vaccination Drive-Ujjain</h1> <h3>Registered Recipients</h3> </center> {% block content %}{% endblock %} <table id="tb" style=" font-size : 12px"> <tr> <th>Reference Number</th> <th>Name</th> <th>Mobile number</th> <th>Aadhar card number</th> <th>Vaccine name</th> <th>Update</th> <th>Delete</th> </tr> {% for value in vaccine_dict.values() %} <tr> <td>{{value.reference_number}}</td> <td>{{value.name}}</td> <td>{{value.mobile_number}}</td> <td>{{value.aadhar_card_number}}</td> <td>{{value.vaccine_name}}</td> <td><a href={{url_for("update",reference_number=value.reference_number)}}> Update </a></td> <td><a href={{url_for("deleteRecord",reference_number=value.reference_number)}}> Delete </a></td> </tr> {% endfor %} </table><br><br> {% block home %}{% endblock %} <content> </content> </body> </html>
由于根据我们的设计,接种人记录表在每个模块(创建、删除和更新)中都是可见的,因此我们在模板base.html 中编写了它的 HTML 代码,这样我们就不必在每个功能页面中重复编写接种人记录表。我们已经应用了 jinja 2 的for循环语法来动态添加表行。方法 url_for 用于生成动态超链接,它在其第一个参数中接方法的名称。在模板base.html 中,我们为块样式、内容和名称提供了 jinja2 语法,因此继承base.html 的模板将用块样式、内容和名称之间编写的代码替换这些块。
我们已经完成了 Web 应用程序的创建过程。现在剩下的是创建处理请求的方法,以及我们将在渲染后通过这些方法来输出 HTML 模板。
@app.route("/") def index() : return render_template("index.html",vaccine_dict=vaccine_dict)
我们已经将请求**"/“与方法index**绑定,因此每次请求”/"会调用 index 方法。
<!------index.html-------> {% extends "base.html" %} {% block home %} <center> <a href="/register">Register</a> </center> {% endblock%}
index 方法将返回渲染后的 index.html,index.html 扩展 base.html 所以 index.html 有 base.html 和 index.html 的代码。index.html 中 {% block home %} 和 {% endblock %} 之间的代码将替换 base.html 中的"{% block home %} {% endblock %}"
@app.route("/register") def register() : return render_template("register.html",vaccine_dict=vaccine_dict)
我们已经将请求**"/register"与方法register**绑定在一起。
<!------register.html-------> {% extends "base.html" %} {% block style %} .registerDiv{ float : right; top : 0; position : relative; border : 0.5px solid black; justify-content : top; padding : 2px } input{ font-size : 7px; } {% endblock %} {% block content %} <div class="registerDiv"> <form method="POST" action='/registerRecipient' style="font-size : 10px"> Name <input type='text' name='name' style="height : 8px"><br> Mobile Number <input type='text' name='mobileNumber' style="height : 8px"><br> Aadhar Card Number <input type='text' name='aadharCardNumber' style="height : 8px"><br> Vaccine Name <input type='text' name='vaccineName' style="height : 8px" ><br> <br> <center> <button type="Submit">Register</button> </center> </form> </div> {% endblock%} {% block home %} <center> <a href="/">Home</a> </center> {% endblock %}
register方法将返回一个呈现的HTML模板,其中包含将出现在表左侧的注册表。单击 “注册” 按钮,将向服务器发送请求 “/registerRecipient”。
@app.route("/registerRecipient",methods=["POST"]) def registerRecipient() : info={"name" : "","mobile_number":"","aadhar_card_number":"","vaccine_name":""} for key,value in request.form.items() : if key=="name" : info["name"]=value if key=="mobileNumber" : info["mobile_number"]=value if key=="aadharCardNumber" : info["aadhar_card_number"]=value if key=="vaccineName" : info["vaccine_name"]=value errors=[] for key,value in info.items() : if value=="" : errors.append(f"{key} required") if len(errors)>0 : return render_template("error.html",vaccine_dict=vaccine_dict,errors=errors) conn=get_db_connection() cursor=conn.cursor() cursor.execute("insert into vaccination (name,mobile_number,aadhar_card_number,vaccine_name) values(%s,%s,%s,%s)",(info["name"],info["mobile_number"],info["aadhar_card_number"],info["vaccine_name"])) info["reference_number"]=cursor.lastrowid vaccine_dict[info["reference_number"]]=info conn.commit() conn.close() return render_template("message.html",vaccine_dict=vaccine_dict,message=f"{info['name']} registered with reference number : {info['reference_number']}")
请求**"/registerRecipient"**,首先对前端传过来的参数进行验证,如果验证不通过就返回错误页面提示错误消息,如果验证通过将接种人信息插入数据库,并把数据绑定到vaccine_dict,输出模板展示注册人的信息。
<!----message.html----> {% extends "base.html" %} {% block home %} <center> <p>{{message}}</p> <a href="/">Home</a> </center> {% endblock%}
<!------error.html------> {% extends "base.html" %} {% block home %} <br> <center> {% for error in errors %} <label style="color:red;font-size : 12px">{{error}}</label><br> {% endfor %} <a href="/">Home</a> </center> {% endblock%}
让我们继续开发 Web App 的更新模块。在更新模块中,用户可以通过单击更新超链接来更新除主键之外的任何字段。数据将在vaccine_dict 中更新,并且将执行发SQL 语句更新数据库中的数据。我们将请求**“/update/reference_number”与方法update绑定,该方法将在其参数中接受
reference_number。该REFERENCE_NUMBER**是从Url中传到后台的。 @app.route("/update/<reference_number>") def update(reference_number) : return render_template("update.html",vaccine_dict=vaccine_dict,reference_number=reference_number)
<!----update.html------> {% extends "base.html" %} {% block style %} .updateDiv{ float : right; top : 0; position : relative; border : 0.5px solid black; justify-content : top; padding: 2px } input{ font-size : 7px; } {% endblock %} {% block content %} <div class="updateDiv"> <form method="POST" style="font-size : 10px" action={{url_for("updateRecord",reference_number=reference_number)}}> <label>Reference number : {{reference_number}}</label><br> Name <input type='text' name='name' style="height : 8px"><br> Mobile Number <input type='text' name='mobileNumber' style="height : 8px"><br> Aadhar Card Number <input type='text' name='aadharCardNumber' style="height : 8px"><br> Vaccine Name <input type='text' name='vaccineName' style="height : 8px" ><br> <br> <center> <button type="Submit">Update</button> </center> </form> </div> {% endblock %} {% block home %} <center> <a href="/">Home</a> </center> {% endblock%}
update 方法将负责渲染模板update.html,HTML 中的“{{ reference_number }}”将替换为我们将传递给render_template方法的 reference_number 的值。
单击更新按钮时,请求**“updateRecord/reference_number”将被发送到服务器,我们将此请求与updateRecord方法绑定,该方法将负责更新数据结构vaccine_dict 以及数据库中的接种人记录。此方法将输出message.html**文件,它将显示适当的消息,通知用接种人记录已成功更新。请求中的 reference_number 将是接种人的主键。
@app.route("/updateRecord/<reference_number>",methods=["POST"]) def updateRecord(reference_number) : info={} reference_number=int(reference_number) for key,value in request.form.items() : if key=="name" : info["name"]=value if key=="mobileNumber" : info["mobile_number"]=value if key=="aadharCardNumber" : info["aadhar_card_number"]=value if key=="vaccineName" : info["vaccine_name"]=value conn=get_db_connection() cursor=conn.cursor() sql="update vaccination set " flag=False dictInfo=vaccine_dict[reference_number] for key,value in info.items() : if value!="" : s=f'{key}="{value}",' dictInfo[key]=value sql+=s flag=True if flag==True : if sql.endswith(",") : sql=sql[:len(sql)-1] sql+=f' where reference_number={reference_number}' cursor.execute(sql) vaccine_dict[reference_number]=dictInfo conn.commit() conn.close() return render_template("message.html",vaccine_dict=vaccine_dict,message=f"Record registered with reference number : {reference_number} updated")
对于registerRecipient和updateRecipeint方法,我们传递了装饰器的参数 methods 参数**[“POST”]这意味着这些方法只有在请求方法是POST**类型时才会执行,在注册和更新模块的情况下,表单提交按钮发送表单 - data 作为 HTTP POST 请求,因此敏感的表单数据在浏览器的地址栏中将不可见。
现在让我们设计 Web 应用程序的删除模块,我们将** “remove/reference_number”请求与名为delete的方法绑定,其中 reference_number 是接种人的主键,delete 方法将从数据结构vaccine_dict 中删除接种人记录和数据库记录,并将执行结果呈现模板message.html**,以通知接种人人已被删除。
@app.route("/remove/<reference_number>") def deleteRecord(reference_number) : conn=get_db_connection() cursor=conn.cursor() cursor.execute("delete from vaccination where reference_number=%s",(reference_number,)) vaccine_dict.pop(int(reference_number) ) conn.commit() conn.close() return render_template("message.html",vaccine_dict=vaccine_dict,message=f"Record registered with reference number : {reference_number} deleted")
最后
至此,我们已经成功完成了我们的应用程序,接下来在您的 shell 窗口中执行以下命令。
(vaccinecrudenv) C:\vaccinecrud> set FLASK_APP=vaccinecrud.py (vaccinecrudenv) C:\vaccinecrud> set FLASK_DEBUG=1 (vaccinecrudenv) C:\vaccinecrud> flask run
我们已经将环境变量 FLASK_APP 的值设置为vaccinecrud.py,因此运行命令flask run flask 将运行vaccinecrud.py,我们还将环境变量FLASK_DEBUG 设置为1来启动调试,这样修改代码将不用重启服务器。上述命令将在端口号 5000 上启动,您可以通过http//localhost:5000来访问web应用。