Loading

hellohelp

flask之路【第一篇】请求、认证、路由

⚙️本教程工程文件{ProjectName}:Practice_flask_0618

​ {ProjectName}:Practice_flask_0619


一、flask快速应用

pip install flask

1.1 flask介绍

  • flask框架基于 Werkzeug的wsgi(web服务网关接口)实现,flask自己没有wsgi

  • 用户请求一旦到来就会执行app.__call__方法

  • 写flask标准流程:

from flask import Flask

app=Flask(__name__)

@app.route("/login",endpoint="lgn")    #endpoint为视图函数定义别名,如果不写那endpoint默认等于下边的视图函数名字。
def loggin():   
    print("登录中")
    return "登录了"

@app.route("/index")
def index():
    return "首页"



if __name__ =="main":
    app.run()

💡路由中的endpoint参数为视图函数定义别名,如果不写那endpoint默认等于下边的视图函数名字。

1.2 用户登录示例

主程序

from flask import Flask, request, render_template, redirect, url_for

app = Flask(__name__)

DATA_DIC = {1: {"name": "xx", "age": 79}, 2: {"name": "yy", "age": 9}}


@app.route('/login', methods=['GET', 'POST'])
def login():  # 登录
    if request.method == "GET":
        return render_template("login.html")
    user = request.form['username']
    pwd = request.form['pwd']

    if user == "张三" and pwd == "123":
        return redirect("/index")
    error = "用户名或密码错误"
    return render_template("login.html", error=error)


@app.route('/index', endpoint="idx")
def index():  # 显示信息
    data_dict = DATA_DIC
    return render_template("index.html", data_dict=data_dict)


@app.route('/edit', methods=['GET', 'POST'])
def edit():  # 编辑信息
    nid = request.args.get("nid")
    nid = int(nid)
    if request.method == "GET":
        info = DATA_DIC[nid]
        return render_template("edit.html", info=info)
    username = request.form['user']
    age = request.form['age']
    DATA_DIC[nid] = {"name": username, "age": age}
    return redirect("/index")


@app.route('/delete/<int:nid>')
def delete(nid):  # 删除信息
    del DATA_DIC[nid]
    return redirect(url_for("idx"))


if __name__ == '__main__':
    app.run()

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h1>Login</h1>

<form method="post">
    <!--label>Username</label-->
    <input type="text" name="username" placeholder="用户名">
    <input type="password" name="pwd" placeholder="密码">
    <input type="submit" value="登录"><span style="color: red;">{{ error }}</span>
</form>

</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>

    <table  border="1px" style="margin-top: 10px;border: aqua">
        <thead>
            <tr>
                <th>id</th>
                <th>name</th>
                <th>age</th>
                <th>操作</th>
            </tr>
        </thead>

        <tbody>
            {% for key,value in data_dict.items() %}
                <tr>
                    <td>{{ key }}</td>
                    <td>{{ value.name }}</td>
                    <td>{{ value.age }}</td>
                    <td>
                        <a href="/edit?nid={{ key }}">编辑</a>
                        <a href="/delete/{{ key }}">删除</a>
                    </td>
                </tr>
            {% endfor %}



            </tr>
        </tbody>
    </table>
</body>
</html>

edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Edit</title>
</head>
<body>
<form method="post">
    <input type="text" name="user" value="{{ info.name }}" >
    <input type="text"  name="age" value="{{ info.age }}" >
    <input type="submit"  value="提交" >
</form>
</body>
</html>

二、Http请求与响应

1.GET请求和post请求

(get请求是URL传参)(post请求有两种传参一种是:赋值的形式,如xx=13&yy=999;一种是字典下面会介绍到)

from flask import Flask, request,jsonify

app = Flask(__name__)

# http://127.0.0.1:5000/index
# http://127.0.0.1:5000/index?age=15&pwd=123
@app.route('/index', methods=['GET', 'POST'])
def index():  # put application's code here
    # url 传参,get请求
    age = request.args.get('age')
    pwd = request.args.get('pwd')
    print(age, pwd)
    # post请求,请求体传参:xx=13&yy=999(请求体也可以用json格式),通过request.form.get获取参数
    xx = request.form.get("xx")
    yy = request.form.get("yy")
    print(xx, yy)
    # 也可以即在请求体中传参,也可以同时在请求体中传参
    print(request.json)
    return '成功'

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)

2.POST请求(json的形式,用jsonify序列化)

import hashlib

from flask import Flask, request,jsonify
# import request
app = Flask(__name__)

def get_user_dict():
    user_dict = {}
    with open('db.txt', 'r') as f:
        for line in f:
            line = line.strip()
            token, name = line.split(',')
            user_dict[token] = name
    return user_dict

@app.route('/bili', methods=['POST'])
def bili():  # put application's code here
    '''
    请求的数据格式要求(字典的形式post过来):{"ordered_string":"...."}
    :return:进行数字化签名用户的序列字符串
    '''
    # print(request.json)
    ordered_string=request.json['ordered_string']
    if not ordered_string:
        return jsonify({"status": False, "erro": "参数错误"})
    # 数字化sign签名
    encrypt_string=ordered_string + "56a5a382-b354-47a4-a0b2-ef40a9420cae"
    sign =hashlib.md5(encrypt_string.encode('utf-8')).hexdigest()
    return jsonify({"status": True, "data":sign})

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)

三、session

保存用户对话信息(session登录)

  • session的用法:
#主程序中写入:
app.secret_key = "ss2d5fp8k9d33ll5896633"  # 设置密钥以便用户session时存储cookie
#或者这种写法app.config['SECRET_KEY'] = "ss2d5fp8k9d33ll5896633"

#其他地方获取了user_dict信息以后,判断是否有值
if user_dict:
        # 登录成功+跳转+存储用户session信息
        session['user_info'] = user_dict
        return redirect("/index")
@od_bp.route('/index')
def index():
    # 读取cookie&解密用户信息
    user_info = session.get("user_info")
    print(user_info)
    if not user_info:  # 如果cookie中的session过期了或者没登陆,这个时候user_info是空的,要重定向到登录页面
        return redirect("/login")
    return "订单列表"

四、路由及相关参数

1路由的别名和url_for()的用法

@app.route('/index',endpoint="idx")
def index():  # put application's code here
    data_dict = DATA_DIC
    return render_template("index.html", data_dict=data_dict)

url_for("idx")
  • 通过endpoint可以为路由定义别名

  • 通过url_for("idx")可以获得路由地址,通过视图函数也可以获得即url_for("index")

    url_for("idx")
    url_for("index")  #index指的是index()函数的名字
    

    url_for方法用于生成指定视图函数的URL。它接受视图函数的名称作为参数,并返回该视图函数对应的URL。url_for方法可以接受其他参数,用于生成带有参数的URL。

2 html向路由函数传值的方法

  • href="/edit?nid={{ key }},通过get请求的方法将值传入
@app.route('/edit')                                                 # 路由获取方法一中传来的值
def edit():  # put application's code here
    nid = request.args.get("nid")
    return render_template("index.html")
  • href="/delete/{{ key }}" ,通过url变量转换器<int:arg>的方法(int可以换成其他的参数如string、any等参数类型)
@app.route('/delete/<int:nid>')									  # 路由获取方法二中传来的值
def delete(nid):  # put application's code here                  #注意此处视图函数要接收参数
    del DATA_DIC[nid]
    return redirect(url_for("idx"))                        #重定向的用法

html文件:

<table  border="1px" style="margin-top: 10px;border: aqua">
        <thead>
            <tr>
                <th>id</th>
                <th>name</th>
                <th>age</th>
                <th>操作</th>
            </tr>
        </thead>

        <tbody>
            {% for key,value in data_dict.items() %}                  # for循环的用法
                <tr>
                    <td>{{ key }}</td>
                    <td>{{ value.name }}</td>
                    <td>{{ value.age }}</td>
                    <td>
                        <a href="/edit?nid={{ key }}">编辑</a>           # 方法一
                        <a href="/delete/{{ key }}">删除</a>			   # 方法二
                    </td>
                </tr>
            {% endfor %}
            </tr>
        </tbody>
    </table>

✅总结

  1. flask路由

    @app.route('/login', methods=['GET', 'POST'])
    def login():  # 登录
        pass
    
  2. 路由的参数

    @app.route('/login', methods=['GET', 'POST'],endpoint="loginin")
    def login():  # 登录
        pass
     # 注意:endpoint不能重名
    
  3. 动态路由

    @app.route('/index')
    def index():  
        pass
        
    @app.route('/index/<name>')
    def index(name):  
        pass
    @app.route('/index/<int:nid>')
    def index(nid):  
        pass
    
  4. 获取提交的数据

    from flask import request
    
    @app.route('/index')
    def index():  
        request.args  #GET形式传递的参数
        request.form #post形式提交的参数
    
  5. 返回数据

    @app.route('/index')
    def index():
    	return render_template("模板文件")
    	return jsonify
    	return redirect("/index/") 
    	return redirect(url_for("idx")) 
    	return "...."
    
  6. 模板处理

    {{ x }}
    
    {% for item in list %}
    	{{item}}
    {% endfor %}
    

五、装饰器和实现用户认证登录

1.装饰器的知识点。

# 定义登录验证装饰器函数
# 使用@functools.wraps 使得endpoint不重复,不然返回的__name__全是decorated:详细解释是:
# 如果不加@functools.wraps,auth 装饰器定义了一个内部函数 decorated,应用装饰器时,实际上发生的是 原始 delete 函数被传递给 auth,auth 返回的是 decorated 函数。在装饰后:原始函数名 delete 实际上被替换成了 decorated;但 Flask 的路由装饰器 @app.route 仍然看到的是函数名 delete;然而在内部,这个函数实际上已经被替换为 decorated
# 如果你有多个使用 @auth 装饰的路由,它们都会被命名为 decorated
def auth(func):
    @functools.wraps(func)
    def decorated(*args, **kwargs):
        if not session.get('user_info'):
            return redirect(url_for("login"))
        return func(*args, **kwargs)
    return decorated
#进入删除页面,使用装饰器验证用户是否登录,即是否有session值
#@auth其实是语法糖,相当于 func = auth(func)
@app.route('/delete/<int:nid>')
@auth
def delete(nid):  # put application's code here
    del DATA_DIC[nid]
    return redirect(url_for("index"))

2.拦截器实现用户认证登录(请求钩子)

from flask import Flask,redirect,session,request

def auth():    # 拦截器函数
    if request.path.startswith("/static"):
        # 不让拦截器拦截静态文件
        return

    if request.path=='/login':
        # 继续执行不拦截
        return
    if session.get('user_info'):
        # 继续执行不拦截
        return
    else:
        return redirect("/login")

def get_real_name():
    userinfo = session.get('user_info')
    return userinfo["real_name"]


def create_app():
    app = Flask(__name__)
    app.secret_key = "ss2d5fp8k9d33ll5896633"  # 设置密钥以便用户session时存储cookie

    from .views import account
    from .views import order
    # 注册蓝图
    app.register_blueprint(account.ac_bp)
    app.register_blueprint(order.od_bp)

    # 注册全局模板,传入每个模板可以调用的函数
    app.template_global()(get_real_name)

    app.before_request(auth)          # 拦截器的应用,请求钩子调用拦截器
    return app

两者比较拦截器更实用简单一点

posted @ 2025-07-15 12:59  HordorZzz  阅读(41)  评论(0)    收藏  举报