Flask

Flask第三方组件非常全,适合小型 API服务类项目,但第三方组件运行稳定性相对Django差。

基础知识

Flask安装

pip install flask==2.0.3

Flask库文件

  • Jinjia2:模板渲染库
  • Markupsafe:返回安全标签 只要Flask返回模板或者标签时都会依赖
  • Werkzeug:德文工具 底层是基于 WSGI,Flask项目启动都是基于Werkzeug
  • itsDangerous: 安全地对数据进行签名,以确保其完整性。用于保护Flask的会话Cookie
  • Click用于编写命令行应用程序的框架,提供命令并允许添加自定义管理命令

启动Flask

# 导入Flask类创建Flask应用对象
from flask import Flask

app = Flask(__name__)

# 为Flask应用添加路由
@app.route("/")
def index():  # 与路由绑定的视图函数,视图函数名尽可能保持唯一
    return "Hello world"


if __name__ == "__main__":
    app.run()  # 启动Flask应用

Flask Response

  1. “Hello world” 可直接返回字符串

  2. render_template(“HTML文件”)

  3. redirect(“/home”) 重定向到指定路由,ResponseHeaders中加入了一个 Location:http://url

  4. send_file(“文件路径”) 返回文件

    打开并识别文件内容,自动识别文件类型,在ResponseHeaders中加入Content-Type:文件类型,这些文件类型是可以被客户端识别的,对于不能识别的文件类型,作下载处理。

    如exe文件:x-ms x表示二进制文件 ms表示微软

  5. jsonify(“字符串或者数据类型”)

    返回数据类型为Content-Type:application/json

Flask Request

  • request.form:获取FormData中的数据,可用to_dict()方法转为字典数据类型

  • request.method:获取请求方式

  • request.args:获取url中的数据

  • request.files:获取上传的文件

    my_file = request.files.get("myfile")
    my_file.save("文件保存路径")
    
  • request.json:获取json数据

    获取Content-Type:application/json时提交的数据

  • request.data:获取原始请求体中的数据 b""

    Content-Type无法被识别或不包含Form字眼

  • request.headers

  • request.cookies

  • request.path

  • request.host

  • request.host_url

  • request.url:请求地址

  • request.values:接受所有(GET,POST)请求中的数据,包含了URL和FormData

  • request.url_charset:URL编码格式

  • request.url_root:请求地址,完整的请求地址 host

  • request.url_rule:请求路由地址 /index

用户登录demo

Python

from flask import Flask
from flask import render_template
from flask import request

app = Flask(__name__)

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "GET":
        return render_template("login.html")
    elif request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        print(username, password)
        if username == "jack" and password == "123456":
            return {"msg": "登陆成功"}
if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

Html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录</title>
</head>
<body>
    <body>
        <form action="/login" method="post">
            <span>账号 <input type="text" name="username"></span><br>
            <span>密码 <input type="text" name="password"></span><br>
            <span><input type="submit" value="登录"></span>
        </form>
    </body>
</body>
</html>

Flask Session

Session:服务端的键值对

Cookie:客户端的键值对

交由客户端保管机制:

  1. 开启session[token] = “asdfihasdfjhdsfiohoi” => {”token": “asdfihasdfjhdsfiohoi”}
  2. 序列化字典 => 字符串
  3. 根据secret_key密钥加密字符串

接受反序列化session:

  1. 从cookie中获取key为session的值 “eyJ0b2tlbiI6ImFzZGloaWFzZGhhc2RpdWhhaXNkaCJ9.Y3Oe1w.yWmRzkZcJXKM1IeVYfF97mCgpz4”
  2. 通过secret_key解密 session
  3. 反序列化成字典
from flask import Flask
from flask import render_template
from flask import request

app = Flask(__name__)
app.secret_key = "$^%%&%#$%&^*"  # 设置密钥,如果不设置密钥,使用session会报错


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "GET":
        return render_template("login.html")
    elif request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        print(username, password)
        if username == "jack" and password == "123456":
            session["token"] = "asdihiasdhasdiuhaisdh"
            return redirect("/")
        
@app.route("/")
def index():
    token = session.get("token")
    return "Hello world"


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

Flask Jinja2

  • {{ }} 引用变量数据 执行函数

  • {% %} 逻辑代码

  • for循环

    {% for item in items %}
    	# 逻辑代码
    {% endfor %}
    
  • if 判断

    {% if 判断条件 %}
    	# 逻辑代码
    {% else %}
    	# 逻辑代码
    {% endif %}
    
from flask import Flask
from flask import render_template

app = Flask(__name__)

def fun():
    return "水花兄弟!"


@app.route("/name")
def user():
    users = [
        {"name": "库里", "age": 34, "gender": "男"},
        {"name": "汤普森", "age": 32, "gender": "男"},
        {"name": "格林", "age": 31, "gender": "男"}
    ]
    return render_template("user.html", users=users, fun=fun)


if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table>
        <tr>
            <td>name</td>
            <td>age</td>
            <td>gender</td>
        </tr>
        {% for user in users %}
            <tr>
                <td>{{ user.name }}</td>
                <td>
                    {% if user.age >= 32 %}
                    {{ fun() }}
                    {% else %}
                    {{ user.age }}
                    {% endif %}
                </td>
                <td>{{ user.gender }}</td>
            </tr>
        {% endfor %}
    </table>
</body>
</html>

注意

  1. 变量为dict类型时,可用key.valuedict[key]或者dict.get(key)获取值
  2. 函数可作为变量传入后调用

Flask 路由参数

route()中的参数
  1. endpoint不能重复,对应视图函数 默认是视图函数名 视图函数与路由对应关系 url_for 反向创建url

  2. methods 允许亲求的方式 ["GET", "POST", "DELETE", "PUT"]

  3. redirect_to 永久重定向 ,没有进入视图直接跳转

  4. strict_slashes 是否严格要求路由匹配规则

    为True时:“/url/“是不被允许的,只允许”/url”

    为False时:"/url/“和”/url"都可以

  5. default={"nid": 123} 默认参数,视图函数中func(nid)一定要接受传参

动态路由参数
  • 接收多个参数
@app.route("/pages/<int:page>_<int:row>")
def pages(page, row):
    print(page, row)
    return "200 ok"

Flask实例化配置

  • template_folder:模板存放路径,默认为templates
  • static_folder:静态文件存放路径,默认值为static
  • static_url_path:静态文件访问路径,默认值为/static
  • static_host:静态文件访问服务HOST => 指向到另一台服务器
from flask import Flask

app = Flask(
    __name__,
    template_folder="templates",
    static_folder="static",
    static_url_path="/static",
    static_host="xxxxx"
)

Flask对象Config配置

DEBUG模式:开启编辑时代码重启,Log打印级别最低,错误信息透传

app.config["DEBUG"] = True

TESTING模式:无限接近生产环境,代码编辑不会重启,Log级别较高,错误信息不再透传

app.config["TESTING"] = False

SESSION_COOKIE_NAME:浏览器中session的名称,第一个字符不能是空格

app.config["SESSION_COOKIE_NAME"] = "session"

Flask Config快速配置

class DebugConfig:
    DEBUG = True
    SECRET_KEY = "asdhugoiasd^%$$#$%#&^%7"
from settings import DebugConfig

app = Flask(__name__)
# app.secret_key = "$^%%&%#$%&^*"
app.config.from_object(DebugConfig)

Flask 蓝图 BluePrint

蓝图作用:功能隔离,路由隔离

新建app01文件夹,下新增views.py文件、templates、static文件夹等

url_prefix:表示URL前缀,用于隔离相同URL

user:表示蓝图名称,不能重复,保证在app中是唯一的

template_folder:默认是最外层项目templates,如需设置内部文件夹,则template_folder=app01/templates

# views.py
# 蓝图
from flask import Blueprint

# BluePrint 当作一个不能够run的Flask
user = Blueprint("user", __name__, url_prefix="/user")


@user.route("/login")
def login():
    return "I am userBP"

在app.py中注册蓝图

from flask import Flask

app = Flask(__name__)

from app01.views import user
# 注册蓝图
app.register_blueprint(user)

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

浏览器中访问app01的login视图:http://127.0.0.1:5000/user/login

Flask特殊装饰器

  • @app.before_request

    请求进入视图函数之前

  • @app.after_request:请求结束,返回响应时

    正常:before_request1 => before_request2 =>视图函数 => after_request2 => after_request1

    异常:before_request1 => after_request2 => after_request1

  • @app.errorhandler(4xx or 5xx):重定义错误信息

    @app.errorhandler(404)
    def error(error_message):
        print(error_message)
        # return f"你访问的{}不存在".format(request.path)  # 自定义信息
        # return redirect("www.baidu.com")  # 重定向
        return send_file("文件路径")  # 返回图片或者其他文件
    

Flask CBV

from flask import Flask

app = Flask(__name__)


@app.route("/")  # FBV
def index():
    return "asbdj"


from flask import views


class Index(views.MethodView):
    def get(self):
        return "GET 200 OK"

    def post(self):
        return "POST 201 OK"

    def put(self):
        return "PUT 200 OK"

    def delete(self):
        return "DELETE 200 OK"

# 注册路由
app.add_url_rule("/user", view_func=Index.as_view(name="user"))

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

监听 端口

0.0.0.0:监听ip地址

端口 - 监听应用程序

包到应用程序的过程:

IOS 5层中的最高层 ——————- 应用

服务器接收到数据:浏览器-9528 b"HTTP 1.1 /GET\r\n" 192.168.14.25:9527

网卡 => 操作系统

操作系统 解包: - 端口9527 - 收到 b"HTTP 1.1 /GET\r\n"

Flask - WSGI 把数据转换成 environ对象,请求原始数据对象,几乎接近于request对象

Flask 接收到 WSGI 转换的environ对象 request_class Flask Request 样式

Flask request对象,如request.form

Flask-Session第三方组件

  • 交由客户端保管机制 - 安全性相对较差 Cookie
  • 原生Session优势是不占用服务器空间
  • Flask-Session - DjangoSession相对一样的数据
  • redis在内网中使用,不要放在公网
# 蓝图
from flask import Blueprint
from flask import session

# BluePrint 当作一个不能够run的Flask
user = Blueprint("user", __name__, url_prefix="/user")


@user.route("/login")
def login():
    session["user"] = "asdugaiushduyh"
    return "I am userBP"


@user.route("")
def index():
    print(session["user"])
    return "session"
from flask import Flask
from flask_session import Session
from redis import Redis

from app01.views import user

app = Flask(__name__)
app.secret_key = "asdhiuh989"
app.config["SESSION_TYPE"] = "redis"
app.config["SESSION_REDIS"] = Redis(host="106.15.**.**", port=6379, password="******")
# 配置之后
Session(app)
# 蓝图之前
app.register_blueprint(user)



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

Flask请求上下文

该部分主要是阅读源码

  1. 线程安全

    极快解决阻塞问题,保证公共对象的安全性,缺点是非常耗费内存,空间换时间

    import time
    from copy import deepcopy
    from threading import Thread, get_ident
    
    
    class Foo:
        pass
    
    
    local_dict = {}
    
    f = Foo()
    f.num = 0
    
    
    def add_(i):
        local_dict[get_ident()] = deepcopy(f)
        local_dict[get_ident()].num = i
        time.sleep(1)
    
        print(local_dict[get_ident()].num)
    
    
    for i in range(20):
        task = Thread(target=add_, args=(i,))
        task.start()
    
    import time
    from threading import Thread, local
    
    
    class Foo(local):
        pass
       
    
    f = Foo()
    
    f.num = 0
    
    
    def add_(i):
        f.num = i
        time.sleep(1)
           print(f.num)
       
       
    for i in range(20):
           task = Thread(target=add_, args=(i,))
        task.start()
    

    相对使用线程ID保存数据的方式,使用local占用资源更少

  2. 偏函数:将原函数和原函数接收的参数一并返回新函数,在执行新函数时,将参数传入原函数中一并执行。

    from functools import partial
    
    def abfunc(a, b, c):
        return a + b + c
    
    new_fum = partial(abfunc, c=88)
    
    print(new_fum(6, 7))
    
  3. OOP 面向对象

    熟悉掌握相关魔法方法以及重写,如__setitem____getitem__

Web socket

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiucheng18

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值