1、Flask请求
数据库创建之后,我们能把需要的数据查询出来,渲染到页面,但这种查询方式死板,缺乏灵活性,并不能实现数据和页面的交互。
实现页面和数据交互方式有两种:通过路由提交请求、向数据库提交请求
1.1 通过路由提交请求
获取路由上的参数来查询相应的数据
案例:根据路由传入的职位id来查询各个部门的员工信息
# 查询数据
@app.route("/book/<int:id>/")
def book_fun(id):
color = [
'#9cc3e5',
'#f4b183',
'#a8d08d'
]
job = Job.query.get(id) # 获得指定id的职业
person_list = job.job_person_map # 查询指定职位的所有员工
return render_template("book.html", **locals())
<!--前端渲染-->
{% block content %}
<a href="/book/7/"><button class="btn btn-danger">财务部</button></a>
<a href="/book/8/"><button class="btn btn-success">技术部</button></a>
<a href="/book/9/"><button class="btn btn-info">市场部</button></a>
<table class="table table-bordered table-hover col-md-7">
<caption style="text-align: center; font-size: 20px; color: black;">员工信息</caption>
<tr>
<th>职位</th>
<th>用户名</th>
<th>性别</th>
<th>年龄</th>
<th>绩效</th>
</tr>
{% for i in person_list %}
<tr style="color:black; background:{{color[loop.index0%3]}};">
<td>{{ i.person_job_map.j_name }}</td>
<td>{{ i.username }}</td>
<td>{{ i.gender }}</td>
<td>{{ i.age }}</td>
<td>{{ i.score }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
通过简单的路由绑定就可实现各个部门员工信息的查询
1.2 向数据库提交请求
1.2.1 表单请求
表单请求,根据用户输入的姓氏查询员工
@app.route("/book/")
def book_fun():
color = [
'#9cc3e5',
'#f4b183',
'#a8d08d'
]
get_arg = request.args # 获取表单提交的数据
search_content = get_arg.get("keywords") # 根据表单内input的name值,获取输入框中要搜索的内容
r = f"{search_content}%"
person_list = Person.query.filter(Person.nickname.like(r))
return render_template("book.html", **locals())
<!--前端渲染-->
{% block lable %}
员工信息
{% endblock %}
{% block content %}
<div class="col-md-10">
<form class="form form-horizontal">
<div class="form-inline">
<input class="form-control" type="text" name="keywords" placeholder="请输入要查询的内容">
<span>
<button class="btn btn-primary">搜索</button>
</span>
</div>
</form>
</div>
<table class="table table-bordered table-hover col-md-7">
<caption style="text-align: center; font-size: 20px; color: black;">员工信息</caption>
<tr>
<th>职位</th>
<th>用户名</th>
<th>性别</th>
<th>年龄</th>
<th>绩效</th>
</tr>
{% for i in person_list %}
<tr style="color:black; background:{{color[loop.index0%3]}};">
<td>{{ i.person_job_map.j_name }}</td>
<td>{{ i.nickname }}</td>
<td>{{ i.gender }}</td>
<td>{{ i.age }}</td>
<td>{{ i.score }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
1.2.2 提交数据及添加文件
添加员工信息,保存员工的基本信息和头像图片
@app.route("/add_person/", methods=["GET", "POST"]) # flask 默认只允许get请求,不允许post请求,若要执行post请求则需要设置
def add_person():
job_list = Job.query.all() # 查询所有职位的类型,在页面中的职位选择器中显示
if request.method == "POST": # 判断是否是POST请求
data = request.form # 接收post请求参数
username = data.get("username") # 根据表单中各个元素的name值来获取用户输入的值
password = data.get("password")
nickname = data.get("nickname")
age = data.get("age")
gender = data.get("gender")
phone = data.get("phone")
email = data.get("email")
address = data.get("address")
person_job = data.get("person_job")
file = request.files.get("photo") # 获取要上传的文件对象
db_path = os.path.join(
"images",
file.filename
) # 数据库存储的是文件在服务器的的相对路径
base_dir = os.path.join(os.path.abspath(
os.path.dirname(__file__)
), "static"
) # 静态文件存储的路径
save_path = os.path.join(base_dir, db_path) # 文件在服务器存放的地址
file.save(save_path) # 把用户上传的文件保存到指定路径
p = Person()
p.username = username
p.password = password
p.nickname = nickname
p.age = age
p.gender = gender
p.phone = phone
p.email = email
p.address = address
p.photo = db_path
p.person_job = int(person_job)
p.save()
return redirect("/person/") # 返回指定路由
return render_template("add_person.html", **locals())
<!--前端渲染-->
{% extends "index.html" %}
{% block label %}
添加员工
{% endblock %}
{% block content %}
<!--
enctype 规定在发送到服务器之前应该如何对表单数据进行编码。
在使用包含文件上传控件的表单时,必须使用multipart/form-data。 -->
<form method="post" enctype="multipart/form-data" class="form form-horizontal col-md-6">
<div class="form-group">
<label class="control-label">用户名:</label>
<input class="form-control" type="text" name="username">
</div>
<div class="form-group">
<label class="control-label">密码:</label>
<input class="form-control" type="password" name="password">
</div>
<div class="form-group">
<label class="control-label">姓名:</label>
<input class="form-control" type="text" name="nickname">
</div>
<div class="form-group">
<label class="control-label">性别:</label>
<select class="form-control" name="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
</div>
<div class="form-group">
<label class="control-label">年龄:</label>
<input class="form-control" type="number" name="age">
</div>
<div class="form-group">
<label class="control-label">电话:</label>
<input class="form-control" type="text" name="phone">
</div>
<div class="form-group">
<label class="control-label">邮箱:</label>
<input class="form-control" type="text" name="email">
</div>
<div class="form-group">
<label class="control-label">头像:</label>
<input class="form-control" type="file" name="photo">
</div>
<div class="form-group">
<label class="control-label">地址:</label>
<textarea class="form-control" name="address"></textarea>
</div>
<div class="form-group">
<label class="control-label">职位:</label>
<select class="form-control" name="person_job">
{% for job in job_list %}
<option value="{{ job.id }}">{{ job.j_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block">提交</button>
</div>
</form>
{% endblock %}
用户上传表单后图片会存储在设置的目录下:
查看员工列表
@app.route("/person/")
def index():
color = [
'#9cc3e5',
'#f4b183',
'#a8d08d'
]
person_list = Person.query.order_by(Person.id.desc()) # 查询并返回所有员工信息到前端
return render_template("person.html", **locals())
<!--前端渲染-->
{% extends "index.html" %}
{% block lable %}
员工管理
{% endblock %}
{% block content %}
<div class="row">
<a href="/add_person/" class="btn btn-primary pull-right">添加用户</a>
</div>
<table class="table table-bordered table-hover col-md-7">
<caption style="text-align: center; font-size: 20px; color: black;">员工信息</caption>
<tr>
<th>职位</th>
<th>用户名</th>
<th>性别</th>
<th>年龄</th>
<th>绩效</th>
</tr>
{% for i in person_list %}
<tr style="color:black; background:{{color[loop.index0%3]}};">
<td>{{ i.person_job_map.j_name }}</td>
<!-- 使用url传参传递该用户id数据到后端 -->
<td><a href="/info/{{ i.id }}/">{{ i.nickname }}</a></td>
<td>{{ i.gender }}</td>
<td>{{ i.age }}</td>
<td>{{ i.score }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
查看员工信息
# 从前端a标签上绑定的路由获取相应的用户id,根据id查询并返回详细数据
@app.route("/info/<int:id>/")
def info(id):
person = Person.query.get(int(id))
return render_template("info.html", **locals())
<!--前端渲染-->
{% extends "index.html" %}
{% block lable %}
员工详细信息
{% endblock%}
{% block content %}
<div class="container">
<table class="table table-bordered" style="width: 1000px;">
<tr>
<td class="col">姓名</td>
<td>{{person.nickname}}</td>
<td>性别</td>
<td>{{ person.gender }}</td>
<td>年龄</td>
<td>{{ person.age }}</td>
<td rowspan="3" width="220"><img src="/static/{{ person.photo }}" alt="用户未上传图片" style="width: 200px;"></td>
</tr>
<tr>
<td>电话</td>
<td>{{person.phone}}</td>
<td>邮箱</td>
<td>{{person.email}}</td>
<td>绩效</td>
<td>{{person.score}}</td>
</tr>
<tr>
<td>地址</td>
<td colspan="5">{{person.address}}</td>
</tr>
<tr>
<td style="text-align: center;vertical-align: middle">
简介
</td>
<td height="200px" colspan="6"></td>
</tr>
</table>
</div>
{% endblock %}
2、Flask会话
会话是指一个终端用户与交互系统进行通讯的过程,例如从浏览器访问服务器开始到关闭浏览器即为一次会话。在一个多用户系统中,通常需要在用户登录后记录用户的数据,用于验证请求者的身份,以此来判断该用户是否有权限访问相应的页面。
2.1 cookie
cookie是服务器下发给浏览器保存到本地,用于验证请求者身份的数据。
2.1.1 创建cookie
from flask import make_response
@app.route("/set_cookie/")
def set_cookie():
# cookie是下发给客户端的
# response是返回给浏览器的工具,所以下发cookie需要在返回内容上
response = make_response(
render_template("index.html", **locals())
) # 将返回的内容转换为response对象
response.set_cookie(
"username", # 键
"laowang", # 值
max_age=60, # cookie的寿命为60秒
path="/index/", # cookie在index的范围下起作用
domain="127.0.0.1", # cookie起作用的域名
secure=True, # 加密传输cookie
httponly=True # 在http协议上使用cookie
) # 设置cookie
return response
简易版
response = redirect("/") # 获取response对象
response.set_cookie("username", username) # 创建cookie
浏览器请求服务器的时候,每次请求会形成数据包,这个包里面描述了整个请求的数据。设置了cookie之后,可以在response header(相应参数)中查看设置的cookie。
cookie参数
参数 | 描述 |
---|---|
key | cookie的键 必填 |
value | cookie的值 必填 |
max_age | cookie的寿命,单位是秒,默认到浏览器关闭 |
expires | 过期时间,和max_age冲突,时间节点2012-3-3 |
path | cookie起作用的范围,默认是/,当前网站的所有页面 |
domain | cookie起作用的域名 |
secure | 是否加密传输cookie |
httponly | 是否只在http协议上使用cookie |
2.1.2 获取cookie
username = request.cookies.get("username")
print(username)
2.1.3 删除cookie
@app.route("/delete_cookie/")
def delete_cookie():
response = make_response(render_template("index.html", **locals()))
response.delete_cookie("username")
return response
2.1.4 案例
用户登录验证,未登录则不可以访问相应的页面。
from functools import wraps
def encrypt_password(password):
"""加密密码"""
md5 = hashlib.md5()
md5.update(password.encode())
result = md5.hexdigest()
return result
def loginValid(fun):
"""登录验证装饰器"""
@wraps(fun) # 使用原来的名称作为返回函数,以便用来装饰多个函数
def inner(*args, **kwargs):
username = request.cookies.get("username") # 获取cookie的username
user_id = request.cookies.get("user_id") # 获取cookie的user_id
if username and user_id:
user = Person.query.get(int(user_id))
if user.username == username:
return fun(user)
return redirect("/login/")
return inner
@app.route("/login/", methods=["GET", "POST"])
def login():
if request.method == "POST":
data = request.form # 获取post数据
username = data.get("username") # 获取用户输入的用户名
password = data.get("password") # 获取用户输入的密码
user = Person.query.filter(Person.username == username).first()
if user:
if encrypt_password(password) == user.password:
response = redirect("/")
response.set_cookie("username", username)
response.set_cookie("user_id", str(user.id))
return response
return render_template("login.html", **locals())
@app.route("/")
@loginValid
def index(user):
return render_template("index.html", **locals())
@app.route("/logout/")
@loginValid
def logout():
"""账号注销,删除cookie"""
response = redirect("/login/")
response.delete_cookie("username")
response.delete_cookie("user_id")
return response
2.2 session
运用加密算法来生成一个唯一标识来标识用户的身份,这个标识可以存放在cookie中,也可以存储在数据库中。session在flask框架中被独成一个叫做session的方法,它是一个类字典对象,对session的操作和操作字典类似。session 是采用了加盐加密算法的,需要开发者设定盐值。
2.2.1 加盐配置
app.config["SECRET_KEY"] = "session" # 加盐加密算法,session是盐值,可以自定义。
2.2.2 创建session
from flask import session
response = redirect("/")
response.set_cookie("username", username)
response.set_cookie("user_id", str(user.id))
session["username"] = username # 设置session,存储在cookie中
return response
2.2.3 获取session
session = request.cookies.get("session")
2.2.4 删除session
session.get("username") # 获取session
session.clear() # 清空session