Flask高级应用

Flsak高级应用

1.请求钩子

@app.before_request
def process_request():
    """"
    # 在请求发送过来的时候调用,视图函数执行之前调用
    # 作用:拦截请求,封ip,用户权限认证(cookie seession jwt)
    black_list = []
    if request.remote_addr in black_list:
        # 注意:在请求之前就已经返回响应对象,那么就不会再执行视图函数
        return "IP不允许访问"
    """
    name = "xiaoming"
    g.name = name
    print("before_request 被调用了")

@app.before_first_request
def inital():
    # 作用:实现项目的初始化工作:连接数据库...
    print("before_first_request 被调用了")

@app.route('/')
def hello_world():

    print(g.name)
    g.user_id = 66

    get_userid()
    # 执行视图函数
    return 'Hello World!'

def get_userid():
    print(g.user_id)

# 注意:接受一个响应对象
@app.after_request
def process_response(resp):
    # 视图函数执行之后调用
    # 作用:拦截响应对象,统一设置处理
    print("after_request 被调用了")
    return resp

@app.teardown_request
def process_error(error):
    # 作用:拦截异常,做异常处理,收尾工作
    # error 有值-代表有异常 为空-代表没有异常发生
    print("teardown_request 被调用了")

"""
装饰器两种执行方式:

方法1:语法糖
@app.after_request
def func():
    pass

方法2:装饰器理解成函数
@app.after_request(process_response)

"""
def view_func():
    pass

app.before_request(view_func)

2.蓝图

app = Flask(__name__)

# 1.创建蓝图对象-管理各自子模块 [麻雀虽小五脏俱全 类似app对象]
# 参数1:蓝图名称
# 参数2:导包路径
# 参数3:当前模块url访问前缀
home_bp = Blueprint('home', __name__, url_prefix='/home')

# 蓝图中也能实现钩子函数
# 局部请求钩子-作用范围是在home模块中
@home_bp.before_request
def process_request():
    # request ==> 容器 ==> 请求相关是所有信息
    print("拦截请求对象")

# 反解析函数-获取函数对应的url路由地址
# url_for("函数名称")
# url_for("蓝图名称.函数名称")
# url_for("user.user_func")

# 延迟导包-解决循环导包问题
from . import views

# 2.使用蓝图对象绑定路由和视图函数
from home import home_bp

# 2.使用蓝图对象绑定路由和视图函数
@home_bp.route('/index')
def home_func():
    return "home page"

# 3.在app中`注册蓝图`对象[各自子模块需要被总的Flask应用管理起来]
app.register_blueprint(home_bp)
app.register_blueprint(user_bp)

3.上下文

"""
上下文:相当于一个数据容器
请求上下文:request, session
应用上下文:current_app, g 

生命周期:[请求开始  返回响应]
使用范围:[默认情况只能在视图函数内使用]

Working outside of request context 超出了请求上下文的使用范围
Working outside of application context. 超出了应用上下文的使用范围

# 手动开启应用上下文
with app.app_context():
"""
# print(request) 错误 超出了请求上下文的使用范围

app = Flask(__name__)
app.secret_key = "xapsoop(**"


# with app.app_context():
#     print(current_app)

# with app.request_context("模拟前端请求"):
#     print(request)


@app.route('/index')
def index():
    # 请求上下文
    print(request.url)
    print(request.method)

    session["name"] = 'zs'
    print(session.get('name'))

    # 应用上下文
    # current_app 当前运行的app对象
    # 作用:当其他模块无法导入app的时候,使用current_app代替app
    print(current_app.url_map)

    # g 预留给程序的容器, 【重点】
    # 1.方便在`钩子函数`和`视图函数`之间进行参数传递
    # 2.方便在`视图函数`和自定义的`函数`之间进行参数传递
    # g 对象生命周期 本次请求[请求开始 返回响应] 特点下一次请求在访问g对象中的数据将会被清空
    g.user_name = 'curry'

    # 别的模块中的函数也能使用g对象提取保存的内容
    get_username()

    return 'Hello World!'


@app.route('/profile')
def profile():
    # 报错 user_name属性不存在
    # 原因:每一次请求都会清空g对象,之前保存的数据就不存在了
    # print(g.user_name)
    pass

问题1: 上下文变量是否为全局变量?
不是全局变量, web服务器会通过多线程并发调用web应用, 而全局变量会被所有线程共享, 无法记录并发的多个请求数据上下文机制实现了线程隔离(LocalStack类型, 本质是字典, key是线程id, 值是上下文变量), 每个线程存取自己的数据, 相互不影响 请求1 -> 线程1 -> request = 请求1请求2 -> 线程2 -> request = 请求2
问题2: 上下文为什么设置使用范围?
主要目的为节省内存请求开始时, 创建上下文(记录上下文变量);请求结束时, 销毁上下文(将上下文变量删除, 数据占用的空间被释放)拓展阅读: 上下文原理

4.综合认证(统一处理,访问限制)

"""
需求:在请求钩子函数中统一提取用户信息,保存到g对象中,方便在其他视图函数中提取用户信息 【优化代码冗余】
需求:点赞、评论、个人中心视图函数要求必须登录才能访问,首页登录显示登录的用户,否则去登录
判断是否有登录 代码会冗余 -- 装饰器
"""
def login_required(view_func):
    # 防止装饰器修改被装饰函数的名称和文档信息
    @wraps(view_func)
    def wrapper(*args, **kwargs):
        # 1.额外装饰的代码实现
        # 判断是否登录
        if g.user_name and g.user_id:
            # 已经登录
            # 2.执行原函数代码实现
            return view_func(*args, **kwargs)
        else:
            # 未登录
            # 401 权限认证失败
            abort(401)

    return wrapper


# 注意:先装饰路由,再装饰登录装饰器
@app.route('/like')
@login_required
def like():
    # 判断是否有登录
    print("点赞成功")
    return "点赞成功"


@app.before_request
def get_userinfo():
    # 统一提取用户信息,保存到g对象中
    g.user_name = session.get("user_name")
    g.user_id = session.get("user_id")


@app.route('/login')
def login():
    # 用户信息状态保持
    session["user_name"] = "james"
    session["user_id"] = 23
    return 'login success'


@app.route('/')
def index():
    if g.user_name and g.user_id:
        return "欢迎: {}".format(g.user_name)
    else:
        return "<a href='/login'>去登录</a>"


@app.route('/comment')
@login_required
def comment():
    # 判断是否有登录
    print("comment 成功")
    return "comment 成功"


@app.route('/profile')
@login_required
def profile():
    # 判断是否有登录
    print("修改个人资料")
    return "profile page"

5.应用配置

# 方案1:
# 需求:少量配置信息可以通过配置字典添加
# config 本质是字典
# app.config["DEBUG"] = True
# app.config["SECRET_KEY"] = "python38"
# app.config["JSON_AS_ASCII"] = False


# 方案2:[推荐]
# 从配置类中加载配置信息
app.config.from_object(config_dict['pro'])

# 从环境变量中加载配置信息
# app.config.from_envvar()

# 从配置py文件中读取配置信息
# app.config.from_pyfile()


@app.route('/')
def hello_world():
    # 获取配置信息
    print(app.config.get("DEBUG"))
    print(current_app.config.get("SECRET_KEY"))
    print(current_app.config.get("JSON_AS_ASCII"))
    print(current_app.config.get("SQL_URL"))
    return 'Hello World!'

工厂模式

class BaseConfig(object):
    """配置类父类"""
    # session混淆加密字符串
    SECRET_KEY = "python666"
    # 不允许中文转换成ASCII编码
    JSON_AS_ASCII = False

class DevelopmentConfig(BaseConfig):
    """开发模式配置信息"""
    # 开启调试模式
    DEBUG = True

    # SQL连接信息
    SQL_URL = "127.0.0.1"
    SQL_PORT = 3306

class ProductionConfig(BaseConfig):
    """生成模式配置信息"""
    # 减少io开销
    DEBUG = False

    # SQL数据库连接信息
    SQL_URL = "192.168.22.33"
    SQL_PORT_MASTER = 3306
    SQL_PORT_SLAVE = 8306

class TestingConfig(BaseConfig):
    """测试环境配置信息"""
    DEBUG = True
    TESTING = True

# 给别的模块调用提供一个接口
config_dict = {
    "dev": DevelopmentConfig,
    "pro": ProductionConfig,
    "test": TestingConfig
}
# 23设计模式 https://yq.aliyun.com/topic/122
# 单例设计模式[补充]  工厂设计模式  装饰器设计模式  中间人设计思想(生产者消费者) MVC MVT MVVM....
# 传入了不同的配置参数,得到不同的配置类,给app添加不同的配置信息,进而得到不同环境下的app对象
def create_app(config_name):
    """工厂方法"""

    app = Flask(__name__)

    # 方案2:[推荐]
    # 1.从配置类中加载配置信息
    app.config.from_object(config_dict[config_name])

    # 2.从环境变量中加载隐私配置,如果存在相同的配置信息,后加载的会覆盖之前加载的配置信息
    # /Users/chenqian/Desktop/深圳38期Flask项目/Flask基础day02/03-代码/secret_config.py
    # 添加环境变量配置信息需要填写绝对路径
    # slient=True 即使未配置环境变量也不会报错
    # export CONFIG 路径
    app.config.from_envvar("CONFIG", slient=True)

    return app

# 开发环境的app对象
app = create_app("dev")

# 生成环境的app对象
# app = create_app("pro")
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值