Flask-- (四) Flask请求和会话

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参数

参数描述
keycookie的键 必填
valuecookie的值 必填
max_agecookie的寿命,单位是秒,默认到浏览器关闭
expires过期时间,和max_age冲突,时间节点2012-3-3
pathcookie起作用的范围,默认是/,当前网站的所有页面
domaincookie起作用的域名
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
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值