Flask

Flask 初识

1、安装

pip install Flask

2、最小的 Flask 应用

from flask import Flask

# 一个Flask类的对象
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

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

运行之后浏览器访问 http://127.0.0.1:5000

3、Flask 配置文件

(1) Flask 配置参数

参数 默认值 解释
DEBUG False 是否开启Debug模式
TESTING False 是否开启测试模式
PROPAGATE_EXCEPTIONS None 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True
PRESERVE_CONTEXT_ON_EXCEPTION None 一两句话说不清楚,一般不用它
SECRET_KEY None 在启用Session的时候,一定要有它
PERMANENT_SESSION_LIFETIME 31 Session的生命周期(天)默认31天
USE_X_SENDFILE False 是否弃用 x_sendfile
LOGGER_NAME None 日志记录器的名称
LOGGER_HANDLER_POLICY always
SERVER_NAME None 服务访问域名
APPLICATION_ROOT None 项目的完整路径
SESSION_COOKIE_NAME session 在cookies中存放session加密字符串的名字
SESSION_COOKIE_DOMAIN None 在哪个域名下会产生session记录在cookies中
SESSION_COOKIE_PATH None cookies的路径
SESSION_COOKIE_HTTPONLY True 控制 cookie 是否应被设置 httponly 的标志
SESSION_COOKIE_SECURE False 控制 cookie 是否应被设置安全标志
SESSION_REFRESH_EACH_REQUEST True 这个标志控制永久会话如何刷新
MAX_CONTENT_LENGTH None 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码
SEND_FILE_MAX_AGE_DEFAULT 12 hours 默认缓存控制的最大期限
TRAP_BAD_REQUEST_ERRORS False
TRAP_HTTP_EXCEPTIONS False
EXPLAIN_TEMPLATE_LOADING False
PREFERRED_URL_SCHEME http 生成URL的时候如果没有可用的 URL 模式话将使用这个值
JSON_AS_ASCII True
JSON_SORT_KEYS True
JSONIFY_PRETTYPRINT_REGULAR True
JSONIFY_MIMETYPE application/json
TEMPLATES_AUTO_RELOAD None

(2) from_object()

settings.py

# 基础配置
class BaseConfig(object):
    DEBUG = False
    TESTING = False
    DATABASES_URL = 'sqlite://memory:'
    SECRET_KEY = "fiu%&*&TSHWDG^(Y*@HUBCG*&H(*#@*&H(*WH(*&gbuuy)"


# 生产环境
class ProductionConfig(BaseConfig):
    DATABASES_URL = "mysql://root@pro/foo"


# 开发环境
class DevelopmentConfig(BaseConfig):
    DATABASES_URL = "mysql://root@dev/foo"
    DEBUG = True


# 测试环境
class TestingConfig(BaseConfig):
    DATABASES_URL = "mysql://root@test/foo"
    DEBUG = True

app.py

from flask import Flask, render_template, redirect

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')

@app.route('/')
def hello_world():
    return 'Hello World!'

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

(3) from_pyfile()

3-1 settings.py


3-2 app.py

from flask import Flask, render_template, redirect

app = Flask(__name__)
app.config.from_pyfile("python文件名称")

@app.route('/')
def hello_world():
    return 'Hello World!'

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

(4) from_envvar()

app.py

from flask import Flask, render_template, redirect

app = Flask(__name__)
app.config.from_envvar("环境变量名称")

@app.route('/')
def hello_world():
    return 'Hello World!'

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

(5) from_json()

settings.json


app.py

from flask import Flask, render_template, redirect

app = Flask(__name__)
app.config.from_json("json文件名称")

@app.route('/')
def hello_world():
    return 'Hello World!'

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

(6) from_mapping()

app.py

from flask import Flask, render_template, redirect

app = Flask(__name__)
app.config.from_mapping({'DEBUG':True})

@app.route('/')
def hello_world():
    return 'Hello World!'

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

(7) 其他方式

from flask import Flask, render_template, redirect

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/')
def hello_world():
    return 'Hello World!'

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

Flask 路由

@app.route('/user/<username>')
@app.route('/post/<int:post_id>')
@app.route('/post/<float:post_id>')
@app.route('/post/<path:path>')
@app.route('/login', methods=['GET', 'POST'])

# 常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:
DEFAULT_CONVERTERS = {
    'default': UnicodeConverter,
    'string': UnicodeConverter,
    'any': AnyConverter,
    'path': PathConverter,
    'int': IntegerConverter,
    'float': FloatConverter,
    'uuid': UUIDConverter,
}

1、注册路由

(1) 方式一

from flask import Flask, render_template, redirect

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def hello_world():
    return 'Hello World!'

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

(2) 方式二

from flask import Flask, render_template, redirect

app = Flask(__name__)

# 方式二:
def order():
    return 'Order'

app.add_url_rule('/order', view_func=order)

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

(3) 方式三

from flask import Flask, views, jsonify

app = Flask(__name__)

class Login(views.MethodView):
    # 指定请求方法,这里可以省略不写,根据请求方法自动找到对应的方法去执行
    methods = ["GET", "POST"]
    # 对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,依次执行
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "我是Login视图的GET方法", "data": None}
        return jsonify(response_data)

    def post(self):
        response_data = {"code": 200, "msg": "我是Login视图的POST方法", "data": None}
        return jsonify(response_data)

# name其实就是用来填充endpoint的,如果endpoint有值那么name就没有用,且name这个参数是必填的,相当于别名
app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"))
app.run("0.0.0.0", 9527)

2、反向生成url

(1) FBV

from flask import Flask, render_template, redirect, url_for
app = Flask(__name__)

@app.route('/login', methods=['GET', 'POST'], endpoint='u1')
def login():
    return 'login'

@app.route('/loginout', methods=['GET', 'POST'])
def loginout():
    return 'loginout'

@app.route('/index', methods=['GET', 'POST'])
def index():
    v1 = url_for('u1')
    v2 = url_for('loginout')
    v3 = url_for('index')
    print(v1, v2, v3)
    return 'index'

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

(2) CBV

from flask import Flask, views, jsonify, url_for

app = Flask(__name__)

class Login(views.MethodView):
    # 指定请求方法,这里可以省略不写,根据请求方法自动找到对应的方法去执行
    methods = ["GET", "POST"]
    # 对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,依次执行
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "我是Login视图的GET方法", "data": None}
        return jsonify(response_data)

    def post(self):
        response_data = {"code": 200, "msg": "我是Login视图的POST方法", "data": None}
        return jsonify(response_data)

class Index(views.MethodView):
    # 指定请求方法,这里可以省略不写,根据请求方法自动找到对应的方法去执行
    methods = ["GET", "POST"]
    # 对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,依次执行
    decorators = []

    def get(self):
        v1 = url_for('login')
        v2 = url_for('index')
        print(v1, v2)
        response_data = {"code": 200, "msg": "我是Index视图的GET方法", "data": None}
        return jsonify(response_data)

# name其实就是用来填充endpoint的,如果endpoint有值那么name就没有用,且name这个参数是必填的,相当于别名
app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"))
app.add_url_rule("/index", endpoint=None, view_func=Index.as_view(name="index"))

app.run()

3、自定义路由转换器

(1) FBV

from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter

app = Flask(import_name=__name__)

class RegexConverter(BaseConverter):
    """
    自定义URL匹配正则表达式
    """
    def __init__(self, map, regex):
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        :param value:
        :return:
        """
        return int(value)

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        :param value:
        :return:
        """
        val = super(RegexConverter, self).to_url(value)
        return val


# 添加到flask中
app.url_map.converters['regex'] = RegexConverter

@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'

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

(2) CBV

from flask import Flask, views, jsonify, url_for
from werkzeug.routing import BaseConverter

app = Flask(__name__)

# 路由转换器
class RegexConverter(BaseConverter):
    """
    自定义URL匹配正则表达式
    """
    def __init__(self, map, regex):
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        :param value:
        :return:
        """
        return int(value)

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        :param value:
        :return:
        """
        val = super(RegexConverter, self).to_url(value)
        return val


class Login(views.MethodView):
    # 指定请求方法,这里可以省略不写,根据请求方法自动找到对应的方法去执行
    methods = ["GET", "POST"]
    # 对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,依次执行
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "我是Login视图的GET方法", "data": None}
        return jsonify(response_data)

    def post(self):
        response_data = {"code": 200, "msg": "我是Login视图的POST方法", "data": None}
        return jsonify(response_data)


class Index(views.MethodView):
    # 指定请求方法,这里可以省略不写,根据请求方法自动找到对应的方法去执行
    methods = ["GET", "POST"]
    # 对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,依次执行
    decorators = []

    def get(self, nid):
        v1 = url_for('login')
        v2 = url_for('index', nid=nid)
        print(v1, v2)
        response_data = {"code": 200, "msg": "我是Index视图的GET方法", "data": None}
        return jsonify(response_data)

# 将路由转换器添加到flask中
app.url_map.converters['regex'] = RegexConverter

# name其实就是用来填充endpoint的,如果endpoint有值那么name就没有用,且name这个参数是必填的,相当于别名
app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"))
app.add_url_rule("/index/<regex('\d+'):nid>", endpoint=None, view_func=Index.as_view(name="index"))

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

4、app.route() 参数

参数 示例值 说明
rule '/' URL规则
view_func 'index' 视图函数名称
defaults None 默认值,当URL中无参数时,使用defaults={'k': 'v'}为函数提供参数
endpoint None 名称,用于反向生成URL,即: url_for('名称')
methods None 允许的请求方式,如:["GET","POST"]
strict_slashes None 对URL最后的 / 符号是否严格要求,
redirect_to None 重定向到指定地址
subdomain None 子域名访问

(1) redirect_to 重定向

FBV

from flask import Flask

app = Flask(__name__)

@app.route('/old', methods=['GET', 'POST'], redirect_to='/new')
def old():
    return '老功能'

@app.route('/new', methods=['GET', 'POST'])
def new():
    return '新功能'

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

CBV

from flask import Flask, views, jsonify, url_for

app = Flask(__name__)

class OldView(views.MethodView):
    methods = ["GET", "POST"]
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "我是旧方法", "data": None}
        return jsonify(response_data)


class NewView(views.MethodView):
    methods = ["GET", "POST"]
    decorators = []
    def get(self):
        response_data = {"code": 200, "msg": "我是新方法", "data": None}
        return jsonify(response_data)

# name其实就是用来填充endpoint的,如果endpoint有值那么name就没有用,且name这个参数是必填的,相当于别名
app.add_url_rule("/old", endpoint=None, view_func=OldView.as_view(name="login"), redirect_to='/new')
app.add_url_rule("/new", endpoint=None, view_func=NewView.as_view(name="index"))

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

(2) subdomain 子域名访问

修改 host 文件(C:\Windows\System32\drivers\etc)

127.0.0.1   www.xingxing.com
127.0.0.1   api.xingxing.com

FBV

from flask import Flask, views, url_for

app = Flask(__name__)
app.config['SERVER_NAME'] = 'xingxing.com:5000'

@app.route("/", subdomain="api")
def static_index():
    return "static.your-domain.tld"

@app.route("/dynamic", subdomain="<username>")
def username_index(username):
    return username + ".your-domain.tld"

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

CBV

from flask import Flask, views, url_for

app = Flask(__name__)
app.config['SERVER_NAME'] = 'xingxing.com:5000'

class Login(views.MethodView):
    methods = ["GET", "POST"]
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "我是Login视图的GET方法", "data": None}
        return jsonify(response_data)

class Index(views.MethodView):
    methods = ["GET", "POST"]
    decorators = []

    def get(self, username):
        response_data = {"code": 200, "msg": "我是Index视图的GET方法", "data": None}
        return jsonify(response_data)

app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"), subdomain="api")
app.add_url_rule("/index", endpoint=None, view_func=Index.as_view(name="index"), subdomain="<username>")

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

Flask 模型

1、SQLALchemy

(1) 前戏

SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

1-1 安装

pip install sqlalchemy
pip install pymysql

1-2 组成部分

  • Engine,框架的引擎
  • Connection Pooling ,数据库连接池
  • Dialect,选择连接数据库的DB API种类
  • Schema/Types,架构和类型
  • SQL Exprression Language,SQL表达式语言

1-3 链接数据库

SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:

# 1. MySQL-Python
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
        
# 2. pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
    
# 3. MySQL-Connector
mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
    
# 4. cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]

# 更多:http://docs.sqlalchemy.org/en/latest/dialects/index.html

(2) 原生 SQL

2-1 基本使用

from sqlalchemy import create_engine

# 创建链接
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=5)

# 方式一:
cur = engine.execute("INSERT INTO user (username, password) VALUES ('苍井空', '123')")
print(cur.lastrowid)  # 新插入行自增ID

# 方式二:
cur = engine.execute("INSERT INTO user (username, password) VALUES(%s, %s)", [('波多野结衣', '123'), ('小泽玛利亚', '123'), ])

# 方式三:
cur = engine.execute("INSERT INTO user (username, password) VALUES (%(username)s, %(password)s)", username='吉泽明步', password='123')

# 查询
cur = engine.execute('select * from user')
# 获取第一行数据
print(cur.fetchone())
# 获取第n行数据
print(cur.fetchmany(3))
# 获取所有数据
print(cur.fetchall())

2-2 数据库链接池

import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine

# 创建引擎
engine = create_engine(
    "mysql+pymysql://root:123@127.0.0.1:3306/t1?charset=utf8",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
)

# 创建任务(查询....)
def task(arg):
    conn = engine.raw_connection()
    cursor = conn.cursor()
    cursor.execute(
        "select * from t1"
    )
    result = cursor.fetchall()
    cursor.close()
    conn.close()

# 多线程执行
for i in range(20):
    t = threading.Thread(target=task, args=(i,))
    t.start()

2-3 数据库连接池

import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine

# 创建引擎
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=0, pool_size=5)

# 创建任务
def task(arg):
    conn = engine.contextual_connect()
    with conn:
        cur = conn.execute(
            "select * from t1"
        )
        result = cur.fetchall()
        print(result)

# 多线程执行
for i in range(20):
    t = threading.Thread(target=task, args=(i,))
    t.start()

2-4 数据库连接池

import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine
from sqlalchemy.engine.result import ResultProxy

# 创建引擎
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=0, pool_size=5)

# 创建任务
def task(arg):
    cur = engine.execute("select * from t1")
    result = cur.fetchall()
    cur.close()
    print(result)

# 多线程执行
for i in range(20):
    t = threading.Thread(target=task, args=(i,))
    t.start()

(3) 基本数据表操作

3-1 创建单表

from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Date, Enum

Base = declarative_base()

# 创建模型
class UserInfo(Base):
    __tablename__ = 'user_info'
    Gender = ("男", "女", "其他")
    id = Column(Integer, primary_key=True, autoincrement=True, comment="ID")
    nickname = Column(String(64), nullable=False, comment="用户昵称")
    avatar = Column(String(128), comment="用户头像")
    gender = Column(Enum(*Gender), server_default="男", comment="性别")
    birthday = Column(Date, default="2000-01-01", comment="生日")
    identifier = Column(String(64), nullable=False, unique=True, comment="账号")
    credential = Column(String(128), nullable=False, comment="密码凭证")
    data_status = Column(Boolean, default=True, comment="数据状态")
    create_time = Column(DateTime, default=datetime.now, comment="创建时间")

def init_db():
    # 创建链接
	engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=5)
    # 创建表
    Base.metadata.create_all(engine)

def drop_db():
    # 创建链接
	engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=5)
    # 删除表
    Base.metadata.drop_all(engine)

if __name__ == '__main__':
    drop_db()
    init_db()

3-2 创建关系表

from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey, DECIMAL

Base = declarative_base()


# 用户表
class Users(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, autoincrement=True, comment="ID")
    nickname = Column(String(64), nullable=False, comment="用户昵称")
    data_status = Column(Boolean, default=True, comment="数据状态")
    create_time = Column(DateTime, default=datetime.now, comment="创建时间")


# 用户认证表
class Auths(Base):
    __tablename__ = 'auths'
    id = Column(Integer, primary_key=True, autoincrement=True, comment="ID")
    identifier = Column(String(64), nullable=False, unique=True, comment="账号")
    credential = Column(String(128), nullable=False, comment="密码凭证")
    data_status = Column(Boolean, default=True, comment="数据状态")
    create_time = Column(DateTime, default=datetime.now, comment="创建时间")

    user_id = Column(Integer, ForeignKey("users.id"))
    # 与生成表结构无关,仅用于查询方便
    user = relationship("Users", backref='auths')


# 商品分类
class GoodsCategory(Base):
    __tablename__ = 'goods_category'
    id = Column(Integer, primary_key=True, autoincrement=True, comment="ID")
    title = Column(String(64), nullable=False, comment="商品分类名称")
    data_status = Column(Boolean, default=True, comment="数据状态")
    create_time = Column(DateTime, default=datetime.now, comment="创建时间")
    parent_id = Column(Integer, ForeignKey("goods_category.id"))


# 商品表
class Goods(Base):
    __tablename__ = 'goods'
    id = Column(Integer, primary_key=True, autoincrement=True, comment="ID")
    name = Column(String(128), nullable=False, comment="商品名称")
    price = Column(DECIMAL(9, 2), default=0, comment="商品价格")
    data_status = Column(Boolean, default=True, comment="数据状态")
    create_time = Column(DateTime, default=datetime.now, comment="创建时间")
    goods_category_id = Column(Integer, ForeignKey("goods_category.id"))
    # 与生成表结构无关,仅用于查询方便
    goods_category = relationship("GoodsCategory", backref='goods')


# 购物车
class ShoppingCart(Base):
    __tablename__ = 'shopping_cart'
    id = Column(Integer, primary_key=True, autoincrement=True, comment="ID")
    number = Column(Integer, default=1, comment="数量")
    data_status = Column(Boolean, default=True, comment="数据状态")
    create_time = Column(DateTime, default=datetime.now, comment="创建时间")
    goods_id = Column(Integer, ForeignKey("goods.id"))
    user_id = Column(Integer, ForeignKey("users.id"))


def init_db():
    """
    根据类创建数据库表
    :return:
    """
    engine = create_engine(
        "mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8",
        max_overflow=0,  # 超过连接池大小外最多创建的连接
        pool_size=5,  # 连接池大小
        pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
        pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    )

    Base.metadata.create_all(engine)


def drop_db():
    """
    根据类删除数据库表
    :return:
    """
    engine = create_engine(
        "mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8",
        max_overflow=0,  # 超过连接池大小外最多创建的连接
        pool_size=5,  # 连接池大小
        pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
        pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    )

    Base.metadata.drop_all(engine)


if __name__ == '__main__':
    drop_db()
    init_db()

(4) 基本增删改查

4-1 添加数据

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# ---------- 方式一: 单个添加 ----------
obj1 = Users(nickname="苍老师")
session.add(obj1)

# ---------- 方式二: 批量添加 ----------
session.add_all([
    Users(nickname="波老师"),
    Users(nickname="小老师"),
    Auths(identifier="admin_001", credential="password_001", user_id=1),
    Auths(identifier="admin_002", credential="password_002", user_id=2),
])

# 异常捕获
try:
    # 提交事务
    session.commit()
except Exception:
    # 发生异常回滚
    session.rollback()
finally:
    # 关闭session
    session.close()

4-2 删除数据

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# ---------- 方式一: 单个删除 ----------
session.query(Users).filter(Users.id == 1).delete()

# ---------- 方式二: 批量删除 ----------
session.query(Users).filter(Users.id > 3).delete()

# 异常捕获
try:
    # 提交事务
    session.commit()
except Exception as e:
    print(e)
    # 发生异常回滚
    session.rollback()
finally:
    # 关闭session
    session.close()

4-3 修改数据

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 修改数据
session.query(Users).filter(Users.id > 0).update({"nickname": "苍老师"})
session.query(Users).filter(Users.id > 0).update({Users.nickname: Users.nickname + "-我爱你"}, synchronize_session=False)
# session.query(Users).filter(Users.id > 0).update({"age": Users.age + 1}, synchronize_session="evaluate")


# 异常捕获
try:
    # 提交事务
    session.commit()
except Exception as e:
    print(e)
    # 发生异常回滚
    session.rollback()
finally:
    # 关闭session
    session.close()

4-4 查询数据

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.sql import text
from models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 查询出所有用户
r1 = session.query(Users).all()
print(r1)

# 获取指定字段的值
r2 = session.query(Users.nickname.label('xx'), Users.data_status).all()
print(r2)

# 获取用户名为 "苍老师-我爱你" 的所有用户
r3 = session.query(Users).filter(Users.nickname == "苍老师-我爱你").all()
print(r3)

# 获取用户名为 "苍老师-我爱你" 的所有用户
r4 = session.query(Users).filter_by(nickname='苍老师-我爱你').all()
print(r4)

# 获取用户名为 "苍老师-我爱你" 的第一个用户
r5 = session.query(Users).filter_by(nickname='苍老师-我爱你').first()
print(r5)

# 获取用户名为 "苍老师-我爱你" id 小于 100 的所有用户
r6 = session.query(Users).filter(text("id<:value and nickname=:name")).params(value=10, name='苍老师-我爱你').order_by(Users.id).all()
print(r6)

# 获取用户名为 "苍老师-我爱你" 的所有用户
r7 = session.query(Users).from_statement(text("SELECT * FROM users where nickname=:name")).params(name='苍老师-我爱你').all()
print(r7)

(5) 查询常用操作

5-1 条件查询

from sqlalchemy import and_, or_
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0,
                       pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 查询用户昵称为 "test_user" 的所有用户
ret = session.query(Users).filter_by(nickname='test_user').all()
print(ret)

# 查询用户id 大于1 并且昵称为 "test_user" 的所有用户
ret = session.query(Users).filter(Users.id > 1, Users.nickname == 'test_user').all()
print(ret)

# 查询用户id在1~3之间 并且昵称为 "test_user" 的所有用户
ret = session.query(Users).filter(Users.id.between(1, 3), Users.nickname == 'test_user').all()
print(ret)

# 查询用户id为[1,3,4]的所有用户
ret = session.query(Users).filter(Users.id.in_([1, 3, 4])).all()
print(ret)

# 查询用户id为 session.query(Users.id).filter_by(nickname='test_user')) 查询出来的结果
ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(nickname='test_user'))).all()
print(ret)

# and 查询
ret = session.query(Users).filter(and_(Users.id > 3, Users.nickname == 'test_user')).all()
print(ret)

# or 查询
ret = session.query(Users).filter(or_(Users.id < 2, Users.nickname == 'test_user')).all()
print(ret)

# and 查询 和 or 查询结合
ret = session.query(Users).filter(
    or_(
        Users.id < 2,
        and_(Users.nickname == 'test_user', Users.id > 3),
        Users.gender != ""
    )).all()
print(ret)

5-2 通配符查询

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 模糊查询用户昵称以 admin 开头的所有用户
ret = session.query(Users.nickname).filter(Users.nickname.like('admin%')).all()
print(ret)

# 模糊查询用户昵称以 user 结尾的所有用户
ret = session.query(Users.nickname).filter(Users.nickname.like('%user')).all()
print(ret)

# 模糊查询用户昵称包含 _use 的所有用户
ret = session.query(Users.nickname).filter(Users.nickname.like('%_use%')).all()
print(ret)

# 模糊查询用户昵称不以 admin 开头的所有用户
ret = session.query(Users.nickname).filter(~Users.nickname.like('admin%')).all()
print(ret)

5-3 限制查询

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 限制查询
ret = session.query(Users)[1:2]
print(ret)

# 限制查询3条
ret = session.query(Users).limit(3).all()
print(ret, '=================')

# 从第六个开始获取所有
ret = session.query(Users).offset(5).all()
print(ret)

# 从第三个开始获取三条
ret = session.query(Users).offset(2).limit(3).all()
print(ret)

# 获取第三个到第五个数据
ret = session.query(Users.id).slice(2, 5).all()
print(ret)

5-4 排序查询

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 查询所有用户 并根据年龄倒序排列
ret = session.query(Users).order_by(Users.age.desc()).all()
print(ret)

# 查询所有用户 并根据用户年龄倒序排列 如果年龄一样则按照正序排列
ret = session.query(Users).order_by(Users.age.desc(), Users.id.asc()).all()
print(ret)

5-5 分组查询

from sqlalchemy.sql import func
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 根据用户年龄分组
# ret = session.query(Users).group_by(Users.nickname).all()
# print(ret)

ret = session.query(func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.nickname).all()
print(ret)

ret = session.query(func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.nickname).having(func.min(Users.id) > 2).all()
print(ret)

5-6 连表查询

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users, Auths, GoodsCategory, Goods

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 连表
ret = session.query(Users, Auths).filter(Users.id == Auths.user_id).all()
print(ret)

ret = session.query(GoodsCategory).join(Goods).all()
print(ret)

ret = session.query(GoodsCategory).join(Goods, isouter=True).all()
print(ret)

5-7 组合查询

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users, Auths, GoodsCategory, Goods

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()


# 组合
q1 = session.query(Users.nickname).filter(Users.id > 2)
q2 = session.query(Auths.identifier).filter(Auths.user_id < 2)
ret = q1.union(q2).all()
print(ret)

q1 = session.query(Users.nickname).filter(Users.id > 2)
q2 = session.query(Auths.identifier).filter(Auths.user_id < 2)
ret = q1.union_all(q2).all()
print(ret)

(6) 一对多操作

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from flask_models.models import Users, Auths

# 创建引擎对象
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 使用relationship正向查询
v = session.query(Auths).first()
print(v.id)
print(v.user.nickname)

# 使用relationship反向查询
v = session.query(Users).first()
print(v.nickname)
print(v.auths)

(7) 多对多操作

from flask_demo.models import Users, Goods, ShoppingCart, GoodsCategory
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

# 创建链接
engine = create_engine("mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8", max_overflow=5)
Session = sessionmaker(bind=engine)
session = Session()


"""
# 添加数据
session.add(Users(nickname="test_user_1"))
session.commit()

session.add(GoodsCategory(title="数码"))
session.commit()

session.add(Goods(name="小米", price=666, goods_category_id=1))
session.commit()

session.add(ShoppingCart(number=1, goods_id=1, users_id=1))
session.commit()

# 同时操作三张表 - 正向
obj = Users(nickname="xiaoming")
obj.goods_data = [Goods(name="联想", price=888, goods_category_id=1), Goods(name="OPPO", price=333, goods_category_id=1)]
session.add(obj)
session.commit()

# 同时操作三张表 - 反向
obj = Goods(name="华为", price=999, goods_category_id=1)
obj.users_data = [Users(nickname="test_user_4"), Users(nickname="test_user_3")]
session.add(obj)
session.commit()
"""


# 使用relationship正向查询
v = session.query(Users).first()
print(v.nickname)
print(v.goods_data)


# 使用relationship反向查询
v = session.query(Goods).first()
print(v.name, v.price)
print(v.users_data)

(8) 其他

import time
import threading
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine
from sqlalchemy.sql import text, func
from sqlalchemy.engine.result import ResultProxy
from db import Users, Hosts, Hobby, Person, Group, Server, Server2Group

engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 关联子查询
subqry = session.query(func.count(Server.id).label("sid")).filter(Server.id == Group.id).correlate(Group).as_scalar()
result = session.query(Group.name, subqry)
"""
SELECT `group`.name AS group_name, (SELECT count(server.id) AS sid 
FROM server 
WHERE server.id = `group`.id) AS anon_1 
FROM `group`
"""

# 原生SQL
"""
# 查询
cursor = session.execute('select * from users')
result = cursor.fetchall()
# 添加
cursor = session.execute('insert into users(name) values(:value)',params={"value":'wupeiqi'})
session.commit()
print(cursor.lastrowid)
"""

session.close()

2、flask-script

安装

pip install flask-script

(1) 基本使用

from flask_script_demo import create_app
from flask_script import Manager

app = create_app()
manage = Manager(app)

@manage.command
def custom(arg):
    """
    自定义命令: python manage.py customc 123
    """
    print(arg)

@manage.option('-n', '--name', dest='name')
@manage.option('-u', '--url', dest='url')
def cmd(name, url):
    """
    自定义命令:
    python manage.py cmd -n flask-script -u http://www.baidu.com
    python manage.py cmd --name flask-script --url http://www.baidu.com
    """
    print(name, url)

if __name__ == '__main__':
    # app.run()
    manage.run()  # python manage.py runserver

3、flask-sqlalchemy

(1) 前戏

项目目录

安装

pip install flask-sqlalchemy

作用

  1. 将 SQLAlchemy 相关的所有功能都封装到db = flask_sqlalchemy.SQLAlchemy() 对象中

  2. 创建表

  3. 操作表

(2) 创建表

from datetime import datetime
from flask_script_demo import db

# 用户表
class Users(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment="ID")
    nickname = db.Column(db.String(64), nullable=False, comment="用户昵称")
    data_status = db.Column(db.Boolean, default=True, comment="数据状态")
    create_time = db.Column(db.DateTime, default=datetime.now, comment="创建时间")

(3) 离线脚本

"""
Web 运行时, flask程序运行起来,用户通过浏览器访问
离线脚本, 自定义一个py 文件 + 使用flask中定义好的功能
"""
from flask_script_demo import db
from flask_script_demo import create_app
from flask_script_demo.users import models

app = create_app()
with app.app_context():
    # 删除表
    # db.drop_all()
    # 创建表
    # db.create_all()
    # 查询
    data = db.session.query(models.Users).all()
    print(data)

(4) 案例

settings.py

# 基础配置
class BaseConfig(object):
    DEBUG = False
    TESTING = False

    # SQLALCHEMY 相关配置
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:19971215@127.0.0.1:3306/flask_test?charset=utf8'
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_POOL_SIZE = 5
    SQLALCHEMY_POOL_RECYCLE = -1
    SQLALCHEMY_POOL_TIMEOUT = 30

# 开发环境
class DevelopmentConfig(BaseConfig):
    DATABASES_URL = "mysql://root@dev/foo"
    DEBUG = True

manage.py

from flask_script_demo import create_app
from flask_script import Manager

app = create_app()
manage = Manager(app)


# 自定制命令
@manage.command
def custom(arg):
    """
    自定义命令: python manage.py customc 123
    """
    print(arg)


# 自定制命令
@manage.option('-n', '--name', dest='name')
@manage.option('-u', '--url', dest='url')
def cmd(name, url):
    """
    自定义命令:
    python manage.py cmd -n flask-script -u http://www.baidu.com
    python manage.py cmd --name flask-script --url http://www.baidu.com
    """
    print(name, url)


if __name__ == '__main__':
    # app.run()
    manage.run()  # python manage.py runserver

views.py

from flask import views, request, jsonify
from flask_script_demo import db
from flask_script_demo.users import models


# 个人中心接口
class UserInfoView(views.MethodView):
    methods = ["GET"]
    decorators = []

    def get(self):
        response_data = {'code': 200, 'msg': '个人信息', 'data': None}
        obj = db.session.query(models.Users).all()
        print(obj)
        return jsonify(response_data)

flask_script_demo/_init_.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# db 就包含了 app 和 SQLAlchemy 的所有操作
db = SQLAlchemy()


# 创建app
def create_app():
    app = Flask(__name__)
    # app.config["DEBUG"] = True
    app.config.from_object('settings.DevelopmentConfig')

    # 注册蓝图
    from flask_script_demo.users import users
    from flask_script_demo.account import account
    # base_path = "api/v1"
    # app.register_blueprint(users, url_prefix=f"/{base_path}/users")
    # app.register_blueprint(account, url_prefix=f"/{base_path}/account")
    app.register_blueprint(users)
    app.register_blueprint(account)

    # 初始化 db
    db.init_app(app)
    return app

flask_script_demo/users/models.py

from datetime import datetime
from flask_script_demo import db


# 用户表
class Users(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment="ID")
    nickname = db.Column(db.String(64), nullable=False, comment="用户昵称")
    data_status = db.Column(db.Boolean, default=True, comment="数据状态")
    create_time = db.Column(db.DateTime, default=datetime.now, comment="创建时间")

flask_script_demo/users/urls.py

from . import users
from . import views

users.add_url_rule("/login", endpoint=None, view_func=views.LoginView.as_view(name="login"))
users.add_url_rule("/user_info", endpoint=None, view_func=views.UserInfoView.as_view(name="user_info"))

flask_script_demo/users/views.py

from flask import views, request, jsonify
from flask_script_demo import db
from flask_script_demo.users import models


# 登录接口
class LoginView(views.MethodView):
    methods = ["POST"]
    decorators = []

    def post(self):
        response_data = {'code': 200, 'msg': '登录成功', 'data': None}
        print(request.get_json())
        return jsonify(response_data)


# 个人中心接口
class UserInfoView(views.MethodView):
    methods = ["GET"]
    decorators = []

    def get(self):
        response_data = {'code': 200, 'msg': '个人信息', 'data': None}

        obj = db.session.query(models.Users).all()
        print(obj)

        print(request.get_json())
        return jsonify(response_data)

4、flask-migrate

(1) 前戏

作用

  • 做数据库迁移

依赖

  • flask-script
  • flask-sqlalchemy

安装

  • pip install flask-migrate

(2) 基本使用

from flask_script_demo import create_app
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from flask_script_demo import db
app = create_app()
manage = Manager(app)

"""
数据库迁移命令: 
    python manage.py db init
    python manage.py db migrate
    python manage.py db upgrade
"""
Migrate(app, db)
manage.add_command('db', MigrateCommand)

if __name__ == '__main__':
    # app.run()
    manage.run()  # python manage.py runserver

5、自定义组件

Flask 请求

常用方法

方法 示例 说明
request.path /request 获取请求路径
request.method GET 获取请求方式
request.headers Host: 127.0.0.1:5000
Connection: keep-alive
...
获取请求头
request.user_agent Mozilla/5.0 (Windows NT 10.0; WOW64) App... 获取UserAgent
request.host 127.0.0.1:5000 获取请求主机
request.url http://127.0.0.1:5000/request?name=xxx&age=22 获取请求完整链接
request.host_url http://127.0.0.1:5000/ 请求主机URL
request.base_url http://127.0.0.1:5000/request 请求地址
request.full_path /request?name=xxx&age=22 查询字符串
request.url_charset utf-8 请求字符集
request.url_root http://127.0.0.1:5000/ 请求根路由
request.url_rule /request 请求路径
request.args ImmutableMultiDict([('name', 'xxx'), ('age', '22')]) 请求数据
request.data b'' 请求数据
request.get_data 请求数据
request.get_json 请求数据
request.files 请求数据
request.form 请求数据
request.values 请求数据
request.view_args 请求数据
request.cookies 请求Cookies
request.authorization 获取身份认证凭证

python查看一个对象可用的方法:

print(dir(request))

1、GET 请求

(1) FBV

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['GET'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.args ----------
    print(request.args)
    name = request.args.get("name", str)
    age = request.args.get("age", int)

    # ---------- request.values ----------
    print(request.values)
    print(request.values.get("name", str))
    print(request.values.get("age", int))
    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

(2) CBV

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

# 视图函数
class RequestView(views.MethodView):
    methods = ["GET"]
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.args ----------
        print(request.args)
        name = request.args.get("name", str)
        age = request.args.get("age", int)
        
        # ---------- request.values ----------
        print(request.values)
        print(request.values.get("name", str))
        print(request.values.get("age", int))
        
        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

2、POST 请求

(1) FBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['POST'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.form ----------
    print(request.form)
    name = request.form.get("name", default=None, type=str)
    age = request.form.get("age", default=None, type=int)
    
    # ---------- request.values ----------
    print(request.values)
    print(request.values.get("name", default=None, type=str))
    print(request.values.get("age", default=None, type=int))
    
    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

Json 传参

Content-Type: application/json;

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['POST'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.data ----------
    print(request.data, type(request.data))
    request_data_1 = json.loads(request.data)
    print(request_data_1, type(request_data_1))

    # ---------- request.get_data() ----------
    print(request.get_data(), type(request.get_data()))
    request_data_2 = json.loads(request.get_data())
    print(request_data_2, type(request_data_2))

    # ---------- request.get_json() ----------
    print(request.get_json(silent=True), type(request.get_json()))
    request_data = request.get_json()
    name = request_data.get('name', None)
    age = request_data.get('age', None)

    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

(2) CBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["POST"]
    decorators = []

    def post(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.form ----------
        print(request.form)
        name = request.form.get("name", default=None, type=str)
        age = request.form.get("age", default=None, type=int)

        # ---------- request.values ----------
        print(request.values)
        print(request.values.get("name", default=None, type=str))
        print(request.values.get("age", default=None, type=int))

        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

Json 传参

Content-Type: application/json;

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["POST"]
    decorators = []

    def post(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.data ----------
        print(request.data, type(request.data))
        request_data_1 = json.loads(request.data)
        print(request_data_1, type(request_data_1))

        # ---------- request.get_data() ----------
        print(request.get_data(), type(request.get_data()))
        request_data_2 = json.loads(request.get_data())
        print(request_data_2, type(request_data_2))

        # ---------- request.get_json() ----------
        print(request.get_json(silent=True), type(request.get_json()))
        request_data = request.get_json()
        name = request_data.get('name', None)
        age = request_data.get('age', None)

        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

3、PUT 请求

(1) FBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['PUT'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.form ----------
    print(request.form)
    name = request.form.get("name", default=None, type=str)
    age = request.form.get("age", default=None, type=int)
    
    # ---------- request.values ----------
    print(request.values)
    print(request.values.get("name", default=None, type=str))
    print(request.values.get("age", default=None, type=int))
    
    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

Json 传参

Content-Type: application/json;

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['PUT'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.data ----------
    print(request.data, type(request.data))
    request_data_1 = json.loads(request.data)
    print(request_data_1, type(request_data_1))

    # ---------- request.get_data() ----------
    print(request.get_data(), type(request.get_data()))
    request_data_2 = json.loads(request.get_data())
    print(request_data_2, type(request_data_2))

    # ---------- request.get_json() ----------
    print(request.get_json(silent=True), type(request.get_json()))
    request_data = request.get_json()
    name = request_data.get('name', None)
    age = request_data.get('age', None)

    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

(2) CBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["PUT"]
    decorators = []

    def put(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.form ----------
        print(request.form)
        name = request.form.get("name", default=None, type=str)
        age = request.form.get("age", default=None, type=int)

        # ---------- request.values ----------
        print(request.values)
        print(request.values.get("name", default=None, type=str))
        print(request.values.get("age", default=None, type=int))

        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

Json 传参

Content-Type: application/json;

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["PUT"]
    decorators = []

    def put(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.data ----------
        print(request.data, type(request.data))
        request_data_1 = json.loads(request.data)
        print(request_data_1, type(request_data_1))

        # ---------- request.get_data() ----------
        print(request.get_data(), type(request.get_data()))
        request_data_2 = json.loads(request.get_data())
        print(request_data_2, type(request_data_2))

        # ---------- request.get_json() ----------
        print(request.get_json(silent=True), type(request.get_json()))
        request_data = request.get_json()
        name = request_data.get('name', None)
        age = request_data.get('age', None)

        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

4、PATCH 请求

(1) FBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['PATCH'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.form ----------
    print(request.form)
    name = request.form.get("name", default=None, type=str)
    age = request.form.get("age", default=None, type=int)
    
    # ---------- request.values ----------
    print(request.values)
    print(request.values.get("name", default=None, type=str))
    print(request.values.get("age", default=None, type=int))
    
    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

Json 传参

Content-Type: application/json;

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request', methods=['PATCH'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    # ---------- request.data ----------
    print(request.data, type(request.data))
    request_data_1 = json.loads(request.data)
    print(request_data_1, type(request_data_1))

    # ---------- request.get_data() ----------
    print(request.get_data(), type(request.get_data()))
    request_data_2 = json.loads(request.get_data())
    print(request_data_2, type(request_data_2))

    # ---------- request.get_json() ----------
    print(request.get_json(silent=True), type(request.get_json()))
    request_data = request.get_json()
    name = request_data.get('name', None)
    age = request_data.get('age', None)

    response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
    return jsonify(response_data)

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

(2) CBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["PATCH"]
    decorators = []

    def patch(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.form ----------
        print(request.form)
        name = request.form.get("name", default=None, type=str)
        age = request.form.get("age", default=None, type=int)

        # ---------- request.values ----------
        print(request.values)
        print(request.values.get("name", default=None, type=str))
        print(request.values.get("age", default=None, type=int))

        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

Json 传参

Content-Type: application/json;

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["PATCH"]
    decorators = []

    def patch(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        # ---------- request.data ----------
        print(request.data, type(request.data))
        request_data_1 = json.loads(request.data)
        print(request_data_1, type(request_data_1))

        # ---------- request.get_data() ----------
        print(request.get_data(), type(request.get_data()))
        request_data_2 = json.loads(request.get_data())
        print(request_data_2, type(request_data_2))

        # ---------- request.get_json() ----------
        print(request.get_json(silent=True), type(request.get_json()))
        request_data = request.get_json()
        name = request_data.get('name', None)
        age = request_data.get('age', None)

        response_data["msg"] = f"大家好我是{name}我今年{age}岁了"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request", endpoint=None, view_func=RequestView.as_view(name="request"))

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

5、DELETE 请求

(1) FBV

form 传参

Content-Type: multipart/form-data;

from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

@app.route('/request/<int:id>', methods=['DELETE'])
def request_view():
    response_data = {"code": 200, "msg": "success", "data": None}
    # 获取请求参数
    response_data["msg"] = "删除成功"
    return jsonify(response_data)

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

(2) CBV

import json
from flask import Flask, views, jsonify, request

app = Flask(__name__)
app.config['DEBUG'] = True

class RequestView(views.MethodView):
    methods = ["DELETE"]
    decorators = []

    def delete(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        # 获取请求参数
        response_data["msg"] = "删除成功"
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/request/<int:id>", endpoint=None, view_func=RequestView.as_view(name="request"))

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

Flask 响应

1、响应字符串

import json
from flask import Flask, views

app = Flask(__name__)
app.config['DEBUG'] = True

class ResponseView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []


    def get(self):
        return "我是 ResponseView 的 GET 方法"

    def post(self):
        return "我是 ResponseView 的 POST 方法"

    def put(self):
        return "我是 ResponseView 的 PUT 方法"

    def patch(self):
        return "我是 ResponseView 的 PATCH 方法"

    def delete(self):
        return "我是 ResponseView 的 DELETE 方法"

# 注册路由
app.add_url_rule("/response", endpoint=None, view_func=ResponseView.as_view(name="response"))

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

2、响应 Response 对象

from flask import Flask, views, jsonify, request, render_template, make_response

app = Flask(__name__)
app.config['DEBUG'] = True

class ResponseView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []

    def get(self):
        response = make_response(render_template('index.html'))
        response.delete_cookie('key')
        response.set_cookie('key', 'value')
        response.headers['X-Something'] = 'A value'
        return response

    def post(self):
        response = make_response("我是 ResponseView 的 POST 方法")
        response.delete_cookie('key')
        response.set_cookie('key', 'value')
        response.headers['X-Something'] = 'A value'
        return response

    def put(self):
        response = make_response("我是 ResponseView 的 PUT 方法")
        response.delete_cookie('key')
        response.set_cookie('key', 'value')
        response.headers['X-Something'] = 'A value'
        return response

    def patch(self):
        response = make_response("我是 ResponseView 的 PATCH 方法")
        response.delete_cookie('key')
        response.set_cookie('key', 'value')
        response.headers['X-Something'] = 'A value'
        return response

    def delete(self):
        response = make_response("我是 ResponseView 的 DELETE 方法")
        response.delete_cookie('key')
        response.set_cookie('key', 'value')
        response.headers['X-Something'] = 'A value'
        return response


# 注册路由
app.add_url_rule("/response", endpoint=None, view_func=ResponseView.as_view(name="response"))

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

3、返回重定向类型

from flask import Flask, views,  redirect

app = Flask(__name__)
app.config['DEBUG'] = True

# 首页视图函数
class IndexView(views.MethodView):
    methods = ["GET"]
    decorators = []

    def get(self):
        return "我是首页页面"

# 响应视图函数
class ResponseView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []

    def get(self):
        return redirect('/index')

    def post(self):
        return redirect('/index')

    def put(self):
        return redirect('/index')

    def patch(self):
        return redirect('/index')

    def delete(self):
        return redirect('/index')


# 注册路由
app.add_url_rule("/index", endpoint=None, view_func=IndexView.as_view(name="index"))
app.add_url_rule("/response", endpoint=None, view_func=ResponseView.as_view(name="response"))

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

4、返回处理错误码

from flask import Flask, views, abort

app = Flask(__name__)
app.config['DEBUG'] = True


class ResponseView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []

    def get(self):
        return abort(404)

    def post(self):
        return abort(400)

    def put(self):
        return abort(401)

    def patch(self):
        return abort(403)

    def delete(self):
        return abort(500)


# 注册路由
app.add_url_rule("/response", endpoint=None, view_func=ResponseView.as_view(name="response"))

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

5、返回模板

from flask import Flask, views, render_template

app = Flask(__name__)
app.config['DEBUG'] = True

class ResponseView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []

    def get(self):
        return render_template('index.html')

    def post(self):
        return render_template('index.html')

    def put(self):
        return render_template('index.html')

    def patch(self):
        return render_template('index.html')

    def delete(self):
        return render_template('index.html')

# 注册路由
app.add_url_rule("/response", endpoint=None, view_func=ResponseView.as_view(name="response"))

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

6、返回 json 数据

from flask import Flask, views, jsonify

app = Flask(__name__)
app.config['DEBUG'] = True

class ResponseView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []

    def get(self):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 GET 方法", "data": None}
        return jsonify(response_data)

    def post(self):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 POST 方法", "data": None}
        return jsonify(response_data)

    def put(self):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 PUT 方法", "data": None}
        return jsonify(response_data)

    def patch(self):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 PATCH 方法", "data": None}
        return jsonify(response_data)

    def delete(self):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 DELETE 方法", "data": None}
        return jsonify(response_data)

# 注册路由
app.add_url_rule("/response", endpoint=None, view_func=ResponseView.as_view(name="response"))

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

Flask 视图

http://www.bjhee.com/flask-ad4.html

1、视图装饰器

(1) FBV

from functools import wraps
from flask import Flask, request, jsonify, session, abort, Response
from random import choice

app = Flask(__name__)
app.config['DEBUG'] = True
# 在启用Session的时候,一定要有它
SECRET_KEY = '-67=d2cg8@d0zw+c268sj84s61yc$b_e2*e^(i9d-^bb+hbqom'
app.secret_key = SECRET_KEY
app.config['PERMANENT_SESSION_LIFETIME'] = 60


# 定义认证装饰器
def login_required(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        if not 'username' in session:
            abort(401)
        return func(*args, **kwargs)

    return decorated_function


# 登录接口
@app.route('/login', methods=["POST"])
def login():
    response_data = {"code": 200, "msg": "success", "data": None}
    request_data = request.get_json()
    username = request_data.get('username', None)
    password = request_data.get('password', None)
    if not all([username, password]):
        response_data["msg"] = "必填项不能为空"
    if username == "admin" and password == "1234":
        session['username'] = username
    return jsonify(response_data)


# 退出登录接口
@app.route('/logout', methods=["GET"])
@login_required
def logout():
    response_data = {"code": 200, "msg": "success", "data": None}
    session.pop('username', None)
    return jsonify(response_data)


# 个人中心接口
@app.route('/user_info', methods=['GET'])
@login_required
def user_info():
    name = session.get("username")
    print(name)
    response_data = {"code": 200, "msg": "success", "data": None}
    return jsonify(response_data)


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

(2) CBV

from functools import wraps
from flask import Flask, request, views, jsonify, session, abort
from random import choice

app = Flask(__name__)
app.config['DEBUG'] = True
# 在启用Session的时候,一定要有它
SECRET_KEY = '-67=d2cg8@d0zw+c268sj84s61yc$b_e2*e^(i9d-^bb+hbqom'
app.secret_key = SECRET_KEY
app.config['PERMANENT_SESSION_LIFETIME'] = 60


# 定义认证装饰器
def login_required(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        if not 'username' in session:
            abort(401)
        return func(*args, **kwargs)

    return decorated_function


# 登录接口
class LoginView(views.MethodView):
    methods = ["POST"]
    decorators = []

    def post(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        request_data = request.get_json()
        username = request_data.get('username', None)
        password = request_data.get('password', None)
        if not all([username, password]):
            response_data["msg"] = "必填项不能为空"
        if username == "admin" and password == "1234":
            session['username'] = username
        return jsonify(response_data)


# 退出登录接口
class LogoutView(views.MethodView):
    methods = ["GET"]
    decorators = [login_required, ]

    def get(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        session.pop('username', None)
        return jsonify(response_data)


# 个人中心接口
class UserInfoView(views.MethodView):
    methods = ["GET"]
    decorators = []

    def get(self):
        name = session.get("username")
        print(name)
        response_data = {"code": 200, "msg": "success", "data": None}
        return jsonify(response_data)


app.add_url_rule("/login", endpoint=None, view_func=LoginView.as_view(name="login"))
app.add_url_rule("/logout", endpoint=None, view_func=LogoutView.as_view(name="logout"))
app.add_url_rule("/user_info", endpoint=None, view_func=UserInfoView.as_view(name="user_info"))

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

2、URL集中映射

(1) FBV

from functools import wraps
from flask import Flask, jsonify, session, abort, views

app = Flask(__name__)
app.config["DEBUG"] = True
# 在启用Session的时候,一定要有它
SECRET_KEY = '-67=d2cg8@d0zw+c268sj84s61yc$b_e2*e^(i9d-^bb+hbqom'
app.secret_key = SECRET_KEY
app.config['PERMANENT_SESSION_LIFETIME'] = 60


# 定义认证装饰器
def login_required(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        if not 'username' in session:
            abort(401)
        return func(*args, **kwargs)

    return decorated_function


def index():
    response_data = {"code": 200, "msg": "首页", "data": None}
    return jsonify(response_data)


def login():
    response_data = {"code": 200, "msg": "登录成功", "data": None}
    return jsonify(response_data)


def logout():
    response_data = {"code": 200, "msg": "退出登录", "data": None}
    return jsonify(response_data)


def user_info():
    response_data = {"code": 200, "msg": "个人中心", "data": None}
    return jsonify(response_data)


app.add_url_rule('/index', view_func=index, methods=["GET"])
app.add_url_rule('/login', view_func=login, methods=["POST"])
app.add_url_rule('/logout', view_func=logout, methods=["GET"])
app.add_url_rule('/user_info', view_func=login_required(user_info), methods=["GET"])

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

(2) CBV

from functools import wraps
from flask import Flask, request, views, jsonify, session, abort
from random import choice

app = Flask(__name__)
app.config['DEBUG'] = True
# 在启用Session的时候,一定要有它
SECRET_KEY = '-67=d2cg8@d0zw+c268sj84s61yc$b_e2*e^(i9d-^bb+hbqom'
app.secret_key = SECRET_KEY
app.config['PERMANENT_SESSION_LIFETIME'] = 60


# 定义认证装饰器
def login_required(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        if not 'username' in session:
            abort(401)
        return func(*args, **kwargs)

    return decorated_function


# 登录接口
class LoginView(views.MethodView):
    methods = ["POST"]
    decorators = []

    def post(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        request_data = request.get_json()
        username = request_data.get('username', None)
        password = request_data.get('password', None)
        if not all([username, password]):
            response_data["msg"] = "必填项不能为空"
        if username == "admin" and password == "1234":
            session['username'] = username
        return jsonify(response_data)


# 退出登录接口
class LogoutView(views.MethodView):
    methods = ["GET"]
    decorators = [login_required, ]

    def get(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        session.pop('username', None)
        return jsonify(response_data)


# 个人中心接口
class UserInfoView(views.MethodView):
    methods = ["GET"]
    decorators = []

    def get(self):
        name = session.get("username")
        print(name)
        response_data = {"code": 200, "msg": "success", "data": None}
        return jsonify(response_data)


app.add_url_rule("/login", endpoint=None, view_func=LoginView.as_view(name="login"))
app.add_url_rule("/logout", endpoint=None, view_func=LogoutView.as_view(name="logout"))
app.add_url_rule("/user_info", endpoint=None, view_func=UserInfoView.as_view(name="user_info"))

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

3、可插拔视图

(1) 视图类

案例一

app.py

from flask import Flask, render_template, views

app = Flask(__name__)
app.config['DEBUG'] = True

class HelloView(views.View):
    def dispatch_request(self, name=None):
        return render_template('hello-view.html', name=name)

view = HelloView.as_view('helloview')
app.add_url_rule('/helloview', view_func=view)
app.add_url_rule('/helloview/<name>', view_func=view)

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

hello-view.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello-View</title>
</head>
<body>
<h1>Hello-View {{ name }}</h1>
</body>
</html>

我们创建了一个 flask.views.View 的子类,并覆盖了其 dispatch_request() 函数,渲染视图的主要代码必须写在这个函数里。然后我们通过 as_view() 方法把类转换为实际的视图函数,as_view() 必须传入一个唯一的视图名。此后,这个视图就可以由 app.add_url_rule() 方法绑定到路由上了。上例的效果,同本篇第一节中”/hello”路径的效果,完全一样。

这个例子比较简单,只是为了介绍怎么用视图类,体现不出它的灵活性,我们再看个例子:

案例二

app.py

from flask import Flask, render_template, views

app = Flask(__name__)
app.config['DEBUG'] = True

class RenderTemplateView(views.View):
    def __init__(self, template):
        self.template = template

    def dispatch_request(self):
        return render_template(self.template)

app.add_url_rule('/hello', view_func=RenderTemplateView.as_view('hello', template='hello-view.html'))
app.add_url_rule('/login', view_func=RenderTemplateView.as_view('login', template='login-view.html'))

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

hello-view.html

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

login-view.html

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

很多时候,渲染视图的代码都类似,只是模板不一样罢了。我们完全可以把渲染视图的代码重用,上例中,我们就省去了分别定义 hellologin 视图函数的工作了。

(2) 视图装饰器支持

在使用视图类的情况下,视图装饰器要怎么用呢?Flask在0.8版本后支持这样的写法:

from functools import wraps
from flask import Flask, request, views, jsonify, session, abort
from random import choice

app = Flask(__name__)
app.config['DEBUG'] = True
# 在启用Session的时候,一定要有它
SECRET_KEY = '-67=d2cg8@d0zw+c268sj84s61yc$b_e2*e^(i9d-^bb+hbqom'
app.secret_key = SECRET_KEY
app.config['PERMANENT_SESSION_LIFETIME'] = 60


# 定义认证装饰器
def login_required(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        if not 'username' in session:
            abort(401)
        return func(*args, **kwargs)

    return decorated_function


# 登录接口
class LoginView(views.MethodView):
    methods = ["POST"]
    decorators = []

    def post(self):
        response_data = {"code": 200, "msg": "success", "data": None}
        request_data = request.get_json()
        username = request_data.get('username', None)
        password = request_data.get('password', None)
        if not all([username, password]):
            response_data["msg"] = "必填项不能为空"
        if username == "admin" and password == "1234":
            session['username'] = username
        return jsonify(response_data)

# 个人中心接口
class UserInfoView(views.MethodView):
    methods = ["GET"]
    decorators = [login_required, ]

    def get(self):
        name = session.get("username")
        print(name)
        response_data = {"code": 200, "msg": "success", "data": None}
        return jsonify(response_data)

app.add_url_rule("/login", endpoint=None, view_func=LoginView.as_view(name="login"))
app.add_url_rule("/user_info", endpoint=None, view_func=UserInfoView.as_view(name="user_info"))

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

我们只需将装饰器函数加入到视图类变量 decorators 中即可。它是一个列表,所以能够支持多个装饰器,并按列表中的顺序执行。

(3) 请求方法的支持

当我们的视图要同时支持GET和POST请求时,视图类可以这么定义:

class MyMethodView(View):
    methods = ['GET', 'POST']

    def dispatch_request(self):
        if request.method == 'GET':
            return '<h1>Hello World!</h1>This is GET method.'
        elif request.method == 'POST':
            return '<h1>Hello World!</h1>This is POST method.'

app.add_url_rule('/mmview', view_func=MyMethodView.as_view('mmview'))

我们只需将需要支持的HTTP请求方法加入到视图类变量 methods 中即可。没加的话,默认只支持GET请求。

(4) 基于方法的视图

from flask import Flask, views, jsonify

app = Flask(__name__)
app.config['DEBUG'] = True

class UserView(views.MethodView):
    methods = ["GET", "POST", "PUT", "PATCH", "DELETE"]
    decorators = []

    def get(self, user_id):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 GET 方法", "data": None}
        return jsonify(response_data)

    def post(self):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 POST 方法", "data": None}
        return jsonify(response_data)

    def put(self, user_id):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 PUT 方法", "data": None}
        return jsonify(response_data)

    def patch(self, user_id):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 PATCH 方法", "data": None}
        return jsonify(response_data)

    def delete(self, user_id):
        response_data = {"code": 200, "msg": "我是 ResponseView 的 DELETE 方法", "data": None}
        return jsonify(response_data)


user_view = UserView.as_view('user_view')

# 将GET /users/请求绑定到UserAPI.get()方法上,并将get()方法参数user_id默认为None
app.add_url_rule('/user/', view_func=user_view, defaults={'user_id': None}, methods=['GET', ])

# 将POST /users/请求绑定到UserAPI.post()方法上
app.add_url_rule('/user/', view_func=user_view, methods=['POST', ])

# 将/users/<user_id>URL路径的GET,PUT,DELETE请求,
# 绑定到UserAPI的get(), put(), delete()方法上,并将参数user_id传入。
app.add_url_rule('/users/<user_id>', view_func=user_view, methods=['GET', 'PUT', 'DELETE'])

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

如果API多,有人觉得每次都要加这么三个路由规则太麻烦,可以将其封装个函数:

def register_api(view, endpoint, url, primary_id='id', id_type='int'):
    view_func = view.as_view(endpoint)
    app.add_url_rule(url, view_func=view_func, defaults={primary_id: None}, methods=['GET', ])
    app.add_url_rule(url, view_func=view_func, methods=['POST', ])
    app.add_url_rule('%s<%s:%s>' % (url, id_type, primary_id), view_func=view_func, methods=['GET', 'PUT', 'DELETE'])

register_api(UserView, 'users', '/users/', primary_id='user_id')

4、延迟加载视图

当某一视图很占内存,而且很少会被使用,我们会希望它在应用启动时不要被加载,只有当它被使用时才会被加载。也就是接下来要介绍的延迟加载。Flask原生并不支持视图延迟加载功能,但我们可以通过代码实现。这里,我引用了官方文档上的一个实现。

Flask 装饰器

1、flask 基本装饰器

装饰器 说明
@app.errorhandler(404) 错误响应
@app.before_first_request 第一次请求之前执行
@app.before_request 每次请求之前执行
@app.after_request 每次请求之后执行
@app.template_global() 全局方法
@app.template_filter() 全局方法
@app.route('/') 路由

2、基本使用

from flask import Flask

app = Flask(__name__)

@app.errorhandler(404)
def page_not_found(error):
    return 'This page does not exist', 404

@app.before_first_request
def before_first_request_func():
    print("第一次请求之前执行...")

@app.before_request
def before_request_func():
    print("每次请求之前执行...")

@app.after_request
def after_request_func(response):
    print("每次请求之后执行...")
    return response

@app.route('/index')
def index():
    print('index')
    return "index"

@app.route('/order')
def order():
    print('order')
    return "order"

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

3、多个装饰器

from flask import Flask

app = Flask(__name__)

@app.before_first_request
def before_first_request_func():
    print("只有第一次请求之前执行...")

@app.before_request
def before_request_func_1():
    print("每次请求之前执行...1")

@app.before_request
def before_request_func_1():
    print("每次请求之前执行...2")

@app.after_request
def after_request_func_1(response):
    print("每次请求之后执行...1")
    return response

@app.after_request
def after_request_func_2(response):
    print("每次请求之后执行...2")
    return response

@app.route('/index')
def index():
    print('index')
    return "index"

@app.route('/order')
def order():
    print('order')
    return "order"

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

4、实现登录验证

from flask import Flask, request, session, redirect

app = Flask(__name__)
app.secret_key = "hd7y9&*^)*(G^#EG&GBG&WECUPBU(N0u0cj0cgGTF%(G&vb8yby8"

@app.before_request
def check_login():
    if request.path == '/login':
        return None
    user = session.get('user_info')
    if not user:
        return redirect('/login')

@app.route('/login', methods=['GET', 'POST'])
def login():
    print('login')
    return "login"

@app.route('/index')
def index():
    print('index')
    return "index"

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

5、实现全局异常捕获

from flask import Flask, jsonify
from werkzeug import exceptions


app = Flask(__name__)
app.config["DEBUG"] = True

# 方式二 分类
@app.route('/login')
def login():
    return "login"

# 全局异常捕获
@app.errorhandler(Exception)
def exception(error):
    response_data = {"code": 500, "msg": "服务器维护中", "data": None}
    print(type(error))
    print(error)
    if isinstance(error, ValueError):
        response_data["code"] = 400
        response_data["msg"] = "请求值异常"
    elif isinstance(error, exceptions.NotFound):
        response_data["code"] = 404
        response_data["msg"] = "Not Found"

    return jsonify(response_data)

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

Flask wtforms

作用: 用于对python web框架做表单验证。

安装:

pip install wtforms
pip install email_validator

1、用户登录

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')
app.debug = True

class LoginForm(Form):
    name = simple.StringField(
        label='用户名',
        validators=[
            validators.DataRequired(message='用户名不能为空.'),
            validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'}

    )
    pwd = simple.PasswordField(
        label='密码',
        validators=[
            validators.DataRequired(message='密码不能为空.'),
            validators.Length(min=8, message='用户名长度必须大于%(min)d'),
            validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}", 
                              message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')

        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        form = LoginForm()
        return render_template('login.html', form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print('用户提交数据通过格式验证,提交的值为:', form.data)
        else:
            print(form.errors)
        return render_template('login.html', form=form)

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

2、用户注册

from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')
app.debug = True

class RegisterForm(Form):
    name = simple.StringField(
        label='用户名',
        validators=[
            validators.DataRequired()
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'},
        default='alex'
    )

    pwd = simple.PasswordField(
        label='密码',
        validators=[
            validators.DataRequired(message='密码不能为空.')
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

    pwd_confirm = simple.PasswordField(
        label='重复密码',
        validators=[
            validators.DataRequired(message='重复密码不能为空.'),
            validators.EqualTo('pwd', message="两次密码输入不一致")
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

    email = html5.EmailField(
        label='邮箱',
        validators=[
            validators.DataRequired(message='邮箱不能为空.'),
            validators.Email(message='邮箱格式错误')
        ],
        widget=widgets.TextInput(input_type='email'),
        render_kw={'class': 'form-control'}
    )

    gender = core.RadioField(
        label='性别',
        choices=(
            (1, '男'),
            (2, '女'),
        ),
        coerce=int
    )
    city = core.SelectField(
        label='城市',
        choices=(
            ('bj', '北京'),
            ('sh', '上海'),
        )
    )

    hobby = core.SelectMultipleField(
        label='爱好',
        choices=(
            (1, '篮球'),
            (2, '足球'),
        ),
        coerce=int
    )

    favor = core.SelectMultipleField(
        label='喜好',
        choices=(
            (1, '篮球'),
            (2, '足球'),
        ),
        widget=widgets.ListWidget(prefix_label=False),
        option_widget=widgets.CheckboxInput(),
        coerce=int,
        default=[1, 2]
    )

    def __init__(self, *args, **kwargs):
        super(RegisterForm, self).__init__(*args, **kwargs)
        self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球'))

    def validate_pwd_confirm(self, field):
        """
        自定义pwd_confirm字段规则,例:与pwd字段是否一致
        :param field: 
        :return: 
        """
        # 最开始初始化时,self.data中已经有所有的值

        if field.data != self.data['pwd']:
            # raise validators.ValidationError("密码不一致") # 继续后续验证
            raise validators.StopValidation("密码不一致")  # 不再继续后续验证

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        form = RegisterForm(data={'gender': 1})
        return render_template('register.html', form=form)
    else:
        form = RegisterForm(formdata=request.form)
        if form.validate():
            print('用户提交数据通过格式验证,提交的值为:', form.data)
        else:
            print(form.errors)
        return render_template('register.html', form=form)

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

Flask 蓝图

小型应用程序:示例

大型应用程序:示例

Flask 认证

1、基于 session 验证


Flask 权限

Flask 节流

Flask 序列化

import json
from marshmallow import fields, post_load
from marshmallow_sqlalchemy import SQLAlchemySchema, SQLAlchemyAutoSchema, auto_field
from app.users.models import User


# json 序列化
class JsonSerializer(fields.Field):
    def _serialize(self, value, attr, obj, **kwargs):
        print(value)
        try:
            return json.loads(value)
        except Exception:
            return value

    def _deserialize(self, value, attr, data, **kwargs):
        return value


# 用户信息序列化器
class UserSchema(SQLAlchemyAutoSchema):
    appointment_time = auto_field(format='%Y-%m-%d %H:%M:%S')
    timeout = auto_field(format='%Y-%m-%d %H:%M:%S')
    order_info = JsonSerializer()

    class Meta:
        model = User
        # 启用外键关系
        include_fk = False
        # 模型关系外部属性
        include_relationships = False
        # 如果要全换全部字段,就不要声明fields或exclude字段即可
        # fields = []

Flask 分页

# 分页模块(三种方式)
from collections import OrderedDict
from urllib.parse import urlencode
from app.afterservice.error import BeyondMaxValueError


class BasePagination:
    pass


# A.创建自定义分页(根据页码进行分页)
class PageNumberPagination(BasePagination):
    # 默认每页显示的数据条数
    page_size = 15
    # 获取URL参数中设置的每页显示数据条数
    page_size_query_param = 'limit'
    # 获取URL参数中传入的页码key
    page_query_param = 'page'
    # 最大支持的每页显示的数据条数
    max_page_size = 50

    def paginate_queryset(self, queryset, request, serializer=None, view=None):
        """
        param queryset: 根据条件筛选出来的结果
        param request: 请求
        """
        # 获取请求参数
        params = request.args
        page = abs(int(params.get(self.page_query_param, 1)))
        limit = abs(int(params.get(self.page_size_query_param, self.page_size)))
        # if limit > self.max_page_size:
        #     raise BeyondMaxValueError
        # <class 'app.afterservice.models.AfterSalesOrder'>

        self.pagination = queryset.paginate(page, per_page=limit, error_out=False)
        return OrderedDict([
            ('total', self.get_total()),
            ('next', self.get_next_link(request)),
            ('previous', self.get_previous_link(request)),
            ('page', self.get_current_page()),
            ('pages', self.get_pages()),
            ('data', self.serializer_data(serializer=serializer)),
            ('limit', limit)
        ])

    # 获取下一页链接
    def get_next_link(self, request):
        if not self.pagination.has_next:
            return None

        params = dict(request.args)
        params["page"] = self.pagination.next_num
        result = urlencode(params)
        return request.base_url + "?" + result

    # 获取上一页链接
    def get_previous_link(self, request):
        if not self.pagination.has_prev:
            return None

        params = dict(request.args)
        params["page"] = self.pagination.prev_num
        result = urlencode(params)
        return request.base_url + "?" + result

    # 获取总条数
    def get_total(self):
        return self.pagination.total

    # 获取当前页面页数
    def get_current_page(self):
        return self.pagination.page

    # 获取总页数
    def get_pages(self):
        return self.pagination.pages

    # 序列化数据
    def serializer_data(self, serializer=None):
        if serializer:
            return serializer.dump(self.pagination.items, many=True)
        data_list = []
        for item in self.pagination.items:
            del item.__dict__["_sa_instance_state"]
            data_list.append(item.__dict__)
        return data_list


# 实现单例模式
page_number_pagination = PageNumberPagination()

Flask 过滤

Flask Redis

1、基本使用

(1) app.py

from apps import create_app

app = create_app()

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

(2) apps/_init_.py

from flask import Flask
from apps.api import api
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis

db = SQLAlchemy()
redis = FlaskRedis()


# 创建app
def create_app():
    app = Flask(__name__)
    app.config.from_object('settings.DevelopmentConfig')
    # 注册蓝图
    app.register_blueprint(api, url_prefix=f"/api")
    db.init_app(app)
    redis.init_app(app)
    return app

(3) utils/redis_utils.py

import pickle
from apps import redis

class Redis:

    @classmethod
    def write(self, key, value, expire=None):
        """
        写入键值对
        """
        redis.set(key, value, ex=expire)

    @classmethod
    def write_dict(self, key, value, expire=None):
        '''
        将内存数据二进制通过序列号转为文本流,再存入redis
        '''
        redis.set(pickle.dumps(key), pickle.dumps(value), ex=expire)

    @classmethod
    def read_dict(self, key):
        '''
        将文本流从redis中读取并反序列化,返回
        '''
        data = redis.get(pickle.dumps(key))
        if data is None:
            return None
        return pickle.loads(data)

    @classmethod
    def read(self, key):
        """
        读取键值对内容
        """
        value = redis.get(key)
        return value.decode('utf-8') if value else value

    @classmethod
    def hset(self, name, key, value):
        """
        写入hash表
        """
        redis.hset(name, key, value)

    @classmethod
    def delete(self, key):
        return redis.delete(key)

redis_method = Redis()

(4) views.py

Flask 扩展

1、闪现

from flask import Flask, session
from flask import flash, get_flashed_messages

app = Flask(__name__)
app.secret_key = "bdc&HBV&SH97gnsuxb97GH(Hx8jxig&T%W(*hiuhgx99ini"

# 方式一 基于session去做
"""
@app.route('/login')
def login():
    # 设置
    session["msg"] = "xxxxxx"
    return "login"


@app.route('/index')
def index():
    # 阅后即焚,下次在拿的时候就没有了
    msg = session.pop('msg')
    print(msg)
    return "index"
"""

# 方式二 基于 flash, get_flashed_messages (本质放也是基于 session 来实现的)
"""
@app.route('/login')
def login():
    # 设置
    flash("少时诵诗书所所所所所")
    return "login"


@app.route('/index')
def index():
    # 阅后即焚,下次在哪的时候就没有了
    data = get_flashed_messages()
    print(data)
    return "index"
"""


# 方式二 分类
@app.route('/login')
def login():
    # 设置
    flash("少时诵诗书所所所所所", category='x1')
    flash("嘻嘻嘻嘻嘻嘻嘻嘻信息", category='x2')
    return "login"


@app.route('/index')
def index():
    # 阅后即焚,下次在哪的时候就没有了
    data = get_flashed_messages(category_filter=['x1', 'x2'])
    print(data)
    return "index"


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

2、中间件

from flask import Flask

app = Flask(__name__)

@app.route('/login')
def login():
    return "login"

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

class Middleware(object):
    def __init__(self, old_wsgi_app):
        """
        服务端启动时自动执行
        :param old_wsgi_app:
        """
        self.old_wsgi_app = old_wsgi_app

    def __call__(self, *args, **kwargs):
        """
        每次有请求到来的时候执行
        def __call__(self, environ, start_response):
            obj = self.old_wsgi_app(environ, start_response)
            
        :param args:
        :param kwargs:
        :return:
        """
        print('before')
        obj = self.old_wsgi_app(*args, **kwargs)
        print('after')
        return obj

if __name__ == '__main__':
    app.wsgi_app = Middleware(app.wsgi_app)
    app.run()
    """
    1. app.__call__()
    2. app.wsgi_app()
    """

3、信号

Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为。

安装

pip install blinker

(1) 内置信号

信号 说明
request_started = _signals.signal('request-started') 请求到来前执行
request_finished = _signals.signal('request-finished') 请求结束后执行
before_render_template = _signals.signal('before-render-template') 模板渲染前执行
template_rendered = _signals.signal('template-rendered') 模板渲染后执行
got_request_exception = _signals.signal('got-request-exception') 请求执行出现异常时执行
request_tearing_down = _signals.signal('request-tearing-down') 请求执行完毕后自动执行(无论成功与否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down') 应用上下文执行完毕后自动执行(无论成功与否)
appcontext_pushed = _signals.signal('appcontext-pushed') 应用上下文push时执行
appcontext_popped = _signals.signal('appcontext-popped') 应用上下文pop时执行
message_flashed = _signals.signal('message-flashed') 调用flask在其中添加数据时,自动触发

(2) 源码示例

request_started

from flask import Flask
flask.full_dispatch_request

(3) 自定义信号

from flask import Flask, current_app, flash, render_template
from flask.signals import _signals

app = Flask(import_name=__name__)

# 自定义信号
xxxxx = _signals.signal('xxxxx')

def func(sender, *args, **kwargs):
    print(sender)

# 自定义信号中注册函数
xxxxx.connect(func)

@app.route("/x")
def index():
    # 触发信号
    xxxxx.send('123123', k1='v1')
    return 'Index'

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

4、上下文管理

6、session

(1) 配置

方式一:


方式二:


方式三:

from flask import Flask

app = Flask(__name__)
app.config['DEBUG'] = True
app.config['PERMANENT_SESSION_LIFETIME'] = 60
# 在启用Session的时候,一定要有它
SECRET_KEY = '-67=d2cg8@d0zw+c268sj84s61yc$b_e2*e^(i9d-^bb+hbqom'
app.secret_key = SECRET_KEY

(2) 设置 session

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)

# 设置session
@app.route('/')
def set():
    # 设置“字典”键值对(正式开发时候,值需要session.get('user')获取)
    session['username'] = 'admin'
    return 'success'

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

(3) 读取 session

因为session就像字典一样所以,操作它的时候有两种方法:

  • result = session[‘key’] :如果内容不存在,将会报异常
  • result = session.get(‘key’) :如果内容不存在,将返回None(推荐用法)
from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)

# 设置session
@app.route('/')
def set():
    # 设置“字典”键值对
    session['username'] = 'admin'
    return 'success'

# 读取session
@app.route('/get')
def get():
    # session['username']
    # session.get('username')
    return session.get('username')

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

(4) 删除 session

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)

# 设置session
@app.route('/')
def set():
    session['username'] = 'admin'
    return 'success'

# 读取session
@app.route('/get/')
def get():
    # session['username']
    # session.get('username')
    return session.get('username')

# 删除session
@app.route('/delete/')
def delete():
    print(session.get('username'))
    session.pop('username', None)
    # session['username'] = False
    print(session.get('username'))
    return 'success'

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

(5) 清除session

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)

# 设置session
@app.route('/')
def set():
    session['username'] = 'liefyuan'
    return 'success'

# 读取session
@app.route('/get')
def get():
    # session['username']
    # session.get('username')
    return session.get('username')

# 删除session
@app.route('/delete')
def delete():
    print(session.get('username'))
    session.pop('username')
    # 或者
    # session['username'] = False
    print(session.get('username'))
    return 'success'

# 清除session中所有数据
@app.route('/clear')
def clear():
    print(session.get('username'))
    # 清除session中所有数据
    session.clear()
    print(session.get('username'))
    return 'success'

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

(6) 设置 session 过期时间

方式一:

如果没有指定session的过期时间,那么默认是浏览器关闭后就自动结束。session.permanent = True在flask下则可以将有效期延长至一个月。下面有方法可以配置具体多少天的有效期。

  • 如果没有指定session的过期时间,那么默认是浏览器关闭后就自动结束
  • 如果设置了session的permanent属性为True,那么过期时间是31天。
  • 可以通过给 app.config 设置 PERMANENT_SESSION_LIFETIME 来更改过期时间,这个值的数据类型是 datetime.timedelay 类型。

使用的需求:

  • 在登录网页界面,下面有一个“记住我”选项,如果点击了则设置session的有效期长一点。就是设置这个!
@app.route('/')
def set():
    session['username'] = 'admin'
    # 长期有效,一个月的时间有效
    session.permanent = True
    return 'success'

方式二:

一种更先进的配置有效期的方法:(比如配置7天有效)

  • 1.引入包:from datetime import timedelta
  • 2.配置有效期限:app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7) # 配置7天有效
  • 3.设置:session.permanent = True
from flask import Flask, session
from datetime import timedelta
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)  # 配置7天有效


# 设置session
@app.route('/')
def set():
    session['username'] = 'liefyuan'
    session.permanent = True
    return 'success

7、多 app 应用

8、离线脚本

9、参考文档

https://www.cnblogs.com/wupeiqi/articles/7552008.html

posted @ 2023-05-31 09:35  菜鸟程序员_python  阅读(165)  评论(0)    收藏  举报