数据库创建之后,我们能把需要的数据查询出来,渲染到页面,但这种查询方式死板,缺乏灵活性,并不能实现数据和页面的交互。
实现页面和数据交互方式有两种:通过路由提交请求、向数据库提交请求
获取路由上的参数来查询相应的数据
案例:根据路由传入的职位id来查询各个部门的员工信息
# 查询数据
@app.route("/book//" )
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 %}
通过简单的路由绑定就可实现各个部门员工信息的查询
表单请求,根据用户输入的姓氏查询员工
@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 %}
添加员工信息,保存员工的基本信息和头像图片
@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 %}
<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>
<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//" )
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 %}
会话是指一个终端用户与交互系统进行通讯的过程,例如从浏览器访问服务器开始到关闭浏览器即为一次会话。在一个多用户系统中,通常需要在用户登录后记录用户的数据,用于验证请求者的身份,以此来判断该用户是否有权限访问相应的页面。
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 |
username = request.cookies.get("username")
print(username)
@app.route("/delete_cookie/")
def delete_cookie():
response = make_response(render_template("index.html", **locals()))
response.delete_cookie("username")
return response
用户登录验证,未登录则不可以访问相应的页面。
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
运用加密算法来生成一个唯一标识来标识用户的身份,这个标识可以存放在cookie中,也可以存储在数据库中。session在flask框架中被独成一个叫做session的方法,它是一个类字典对象,对session的操作和操作字典类似。session 是采用了加盐加密算法的,需要开发者设定盐值。
app.config["SECRET_KEY"] = "session" # 加盐加密算法,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
session = request.cookies.get("session")
session.get("username") # 获取session
session.clear() # 清空session