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

1、Flask请求

数据库创建之后,我们能把需要的数据查询出来,渲染到页面,但这种查询方式死板,缺乏灵活性,并不能实现数据和页面的交互。

实现页面和数据交互方式有两种:通过路由提交请求、向数据库提交请求

1.1 通过路由提交请求

获取路由上的参数来查询相应的数据

案例:根据路由传入的职位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 %}

Flask-- (四) Flask请求和会话_第1张图片

通过简单的路由绑定就可实现各个部门员工信息的查询

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 %}

Flask-- (四) Flask请求和会话_第2张图片

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 %}
    
    <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 %}

用户上传表单后图片会存储在设置的目录下:

Flask-- (四) Flask请求和会话_第3张图片

查看员工列表

@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 %}

Flask-- (四) Flask请求和会话_第4张图片

查看员工信息

# 从前端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 %}

Flask-- (四) Flask请求和会话_第5张图片

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。

Flask-- (四) Flask请求和会话_第6张图片

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)

Flask-- (四) Flask请求和会话_第7张图片

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

Flask-- (四) Flask请求和会话_第8张图片

2.2.3 获取session
session = request.cookies.get("session")
2.2.4 删除session
session.get("username")  # 获取session
session.clear()  # 清空session

你可能感兴趣的:(Flask-- (四) Flask请求和会话)