zoukankan      html  css  js  c++  java
  • Flask Markup 上下文,request

    在模板渲染中,使用Markup转换变量中的特殊字符

    from flask import Markup

    Markup函数对字符串进行转移处理再传递给render_template()函数

    在浏览器中显示标签代码

    路由地址的反响生成

    通过函数名获得与其绑定的Url地址

    需要使用url_for函数进行反向解析

    with app.text_request_context()
        print(url_for('f_root')) # 输出:/
    app.text_request_context()方法告诉解释器为在其作用域中的代码模拟一个HTTP请求上下文,使其好像被一个HTTP请求所调用

    使用Context上下文
    他是服务器端获得应用及请求相关信息的对象
    1、会话上下文
    会话(session)是一种客户端与服务器端保持状态的解决方案,会话上下文是用来实现这种解决方案的存储结构
    from flask import Flask,session
    from datetime import datetime
    
    app = Flask(__name__)
    
    app.secret_key = 'SET_ME_BEFORE_USE_SESSION'
    
    
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    @app.route('/write_session')
    def wirteSession():
        session['key_time']=datetime.now().strftime('%Y-%m-%d %H:%M:%S')# 将当前时间保存在Session中
        return session['key_time'] # 返回当前时间
    @app.route('/read_session')
    def readSession():
        return session.get('key_time')# 获取上次调用wirteSession时写入的时间并返回

    除了正常的数据保存和读取,flask.session对象还维护自身的状态,通过

    new 判断本次请求的Session是否时新建的

    modified 判断本次请求中是否修改过Session键值

    @app.route('/write_session')
    def wirteSession():
        session['key_time']=time.time() # 将当前时间保存在Session中
        return session.modified # 因为之前进行了Session设置,所以判断本次请求是否被修改过(modified)返回TRUE

    应用全局对象

    from flask import Flask,g
    
    class MYDB():
        def __init__(self):
            print('一个数据库链接已经建立')
    
        def close(self):
            print('数据库已经关闭')
    
    def connect_to_database():
        return MYDB()
    
    def get_db():
        db = getattr(g,'_database',None)
        if db is None:
            db = connect_to_database()
            g._database = db # 存入Flask.g对象中
        return db
    
    @app.teardown_request # 在请求结束时自动被Flask框架调用
    def teardown_db(response):
        db = getattr(g,'_database',None)# 从Flask.g对象中获取对象,检查是否有链接数据库对象,如果有则关闭
        if db is not None:
            db.close()
    可以在请求处理函数的任何地方调用get_db()
    class MYDB():
        def __init__(self):
            print('一个数据库链接已经建立')
    
        def close(self):
            print('数据库已经关闭')
    
    def connect_to_database():
        return MYDB()
    
    def get_db():
        db = getattr(g,'_database',None)
        if db is None:
            db = connect_to_database()
            g._database = db # 存入Flask.g对象中
        return db
    
    @app.teardown_request
    def teardown_db(response):
        db = getattr(g,'_database',None)# 从Flask.g对象中获取对象
        if db is not None:
            db.close()
    def login():
        db=get_db()  # 第一次调用getdb  创建数据库链接
        session['has_login']=True
        # 使用db检查数据库中的用户名和密码
    def view_list():
        if 'has_login' not in session:
            login()
        db = get_db() # 第二次调用get_db()# 直接复用之前建立的链接
        # 使用db 从数据库查询数据,返回teardown_db()将会被自动调用

    请求上下文生命周期

    from flask import Flask, g, request
     
    app = Flask(__name__)
     
    @app.before_request
    def before_request():
        print 'before request started'
        print request.url
     
    @app.before_request
    def before_request2():
        print 'before request started 2'
        print request.url
        g.name="SampleApp"
     
    @app.after_request
    def after_request(response):
        print 'after request finished'
        print request.url
        response.headers['key'] = 'value'
        return response
     
    @app.teardown_request
    def teardown_request(exception):
        print 'teardown request'
        print request.url
     
    @app.route('/')
    def index():
        return 'Hello, %s!' % g.name
     
    if __name__ == '__main__':
        app.run(host='0.0.0.0', debug=True)

    访问”http://localhost:5000/”后,会在控制台输出:

    before request started
    http://localhost:5000/
    before request started 2
    http://localhost:5000/
    after request finished
    http://localhost:5000/
    teardown request
    http://localhost:5000/

    request对象只有在请求上下文的生命周期内才可以访问。离开了请求的生命周期,其上下文环境也就不存在了,自然也无法获取request对象。而上面介绍的几个由上下文装饰器修饰的Hook函数,会挂载在请求生命周期内的不同阶段,所以其内部可以访问request对象。

    构建请求上下文环境

    我们使用Flask的内部方法”request_context()”来构建一个客户端请求上下文。

    from werkzeug.test import EnvironBuilder
     
    ctx = app.request_context(EnvironBuilder('/','http://localhost/').get_environ())
    ctx.push()
    try:
        print request.url
    finally:
        ctx.pop()

    “request_context()”会创建一个请求上下文”RequestContext”类型的对象,其需接收”werkzeug”中的”environ”对象为参数。”werkzeug”是Flask所依赖的WSGI函数库

    我们可以在客户端的请求之外访问request对象,其实此时的request对象即是刚创建的请求上下文中的一个属性”request == ctx.request”。启动Flask时,控制台仍然可以打印出访问地址”http://localhost/”。上面的代码可以用with语句来简化:

    from werkzeug.test import EnvironBuilder
     
    with app.request_context(EnvironBuilder('/','http://localhost/').get_environ()):
        print request.url

    请求上下文的实现方式

    对于Flask Web应用来说,每个请求就是一个独立的线程。请求之间的信息要完全隔离,避免冲突,这就需要使用本地线程环境(ThreadLocal),

    ”ctx.push()”方法,会将当前请求上下文,压入”flask._request_ctx_stack”的栈中,同时这个”_request_ctx_stack”栈是个ThreadLocal对象,也就是”flask._request_ctx_stack”看似全局对象,其实每个线程的都不一样。请求上下文压入栈后,再次访问其都会从这个栈的顶端通过”_request_ctx_stack.top”来获取,所以取到的永远是只属于本线程中的对象,这样不同请求之间的上下文就做到了完全隔离。请求结束后,线程退出,ThreadLocal线程本地变量也随即销毁,”ctx.pop()”用来将请求上下文从栈里弹出,避免内存无法回收。

    ——————————————————————————————————————————————————————————————————————

    主要是在服务端获得从客户端提交的数据,包括url参数,表单数据,cookies等

    from flask import Flask,request,url_for,redirect
    
    app = Flask(__name__)
    
    @app.route('/redirect_url')
    def redirect_url():
        next = request.args.get('next') or url_for('index')
        return redirect(next)
    
    @app.route('/echo_url')
    def echo_url():
        return request.base_url

    自定义上下文变量和函数

    自定义变量

    from flask import current_app
     
    @app.context_processor
    def appinfo():
        return dict(appname=current_app.name)

    函数返回的是一个字典,里面有一个属性”appname”,值为当前应用的名称。我们曾经介绍过,这里的”current_app”对象是一个定义在应用上下文中的代理。函数用”@app.context_processor”装饰器修饰,它是一个上下文处理器,它的作用是在模板被渲染前运行其所修饰的函数,并将函数返回的字典导入到模板上下文环境中,与模板上下文合并。然后,在模板中”appname”成为了可访问的上下文对象。我们可以在模板中将其输出:

      <p>Current App is: {{ appname }}</p>

    自定义函数

    同理我们可以自定义上下文函数,只需将上例中返回字典的属性指向一个函数即可,下面我们就来定义一个上下文函数来获取系统当前时间:

    import time
     
    @app.context_processor
    def get_current_time():
        def get_time(timeFormat="%b %d, %Y - %H:%M:%S"):
            return time.strftime(timeFormat)
        return dict(current_time=get_time)
      <p>Current Time is: {{ current_time() }}</p>
      <p>Current Day is: {{ current_time("%Y-%m-%d") }}</p>

    应用上下文环境

    current_app代理

    from flask import Flask, current_app
     
    app = Flask('SampleApp')
     
    @app.route('/')
    def index():
        return 'Hello, %s!' % current_app.name

    我们可以通过”current_app.name”来获取当前应用的名称,也就是”SampleApp”。”current_app”是一个本地代理,它的类型是”werkzeug.local. LocalProxy”,它所代理的即是我们的app对象,也就是说”current_app == LocalProxy(app)”。使用”current_app”是因为它也是一个ThreadLocal变量,对它的改动不会影响到其他线程。你可以通过”current_app._get_current_object()”方法来获取app对象。

    既然是ThreadLocal对象,那它就只在请求线程内存在,它的生命周期就是在应用上下文里。离开了应用上下文,”current_app”一样无法使用

    构建应用上下文环境

    同请求上下文一样,我们也可以手动构建应用上下文环境:

    with app.app_context():
        print current_app.name

    “app_context()”方法会创建一个”AppContext”类型对象,即应用上下文对象,此后我们就可以在应用上下文中,访问”current_app”对象了。

    应用上下文Hook函数

    应用上下文也提供了装饰器来修饰Hook函数,不过只有一个”@app.teardown_appcontext”。它会在应用上下文生命周期结束前,也就是从”_app_ctx_stack”出栈时被调用。我们可以加入下面的代码,顺便也验证下,是否应用上下文在每个请求结束时会被销毁。

    @app.teardown_appcontext
    def teardown_db(exception):
        print 'teardown application'

    request的属性

    下面是request可使用的属性,其中黑体是比较常用的。

    • form 
      一个从POST和PUT请求解析的 MultiDict(一键多值字典)。

    • args 
      MultiDict,要操作 URL (如 ?key=value )中提交的参数可以使用 args 属性:

    searchword = request.args.get('key', '')
    • values 
      CombinedMultiDict,内容是formargs。 
      可以使用values替代form和args。

    • cookies 
      顾名思义,请求的cookies,类型是dict。

    • stream 
      在可知的mimetype下,如果进来的表单数据无法解码,会没有任何改动的保存到这个·stream·以供使用。很多时候,当请求的数据转换为string时,使用data是最好的方式。这个stream只返回数据一次。

    • headers 
      请求头,字典类型。

    • data 
      包含了请求的数据,并转换为字符串,除非是一个Flask无法处理的mimetype。

    • files 
      MultiDict,带有通过POST或PUT请求上传的文件。

    • environ 
      WSGI隐含的环境配置。

    • method 
      请求方法,比如POST、GET。

    • path

    • script_root
    • url
    • base_url
    • url_root 
      如果用户请求如下URL: 
      http://www.example.com/myapplication/page.html?x=y 
      以上的参数内容如下:
    名称内容
    path /page.html
    script_root /myapplication
    base_url http://www.example.com/myapplication/page.html
    url http://www.example.com/myapplication/page.html?x=y
    url_root http://www.example.com/myapplication/
      • is_xhr 
        如果请求是一个来自JavaScript XMLHttpRequest的触发,则返回True,这个只工作在支持X-Requested-With头的库并且设置了XMLHttpRequest

      • blurprint 
        蓝本名字。

      • endpoint 
        endpoint匹配请求,这个与view_args相结合,可是用于重构相同或修改URL。当匹配的时候发生异常,会返回None。

      • get_json(force=False, silent=False, cache=True)

      • json 
        如果mimetypeapplication/json,这个参数将会解析JSON数据,如果不是则返回None。 
        可以使用这个替代get_json()方法。

      • max_content_length 
        只读,返回MAX_CONTENT_LENGTH的配置键。

      • module 
        如果请求是发送到一个实际的模块,则该参数返回当前模块的名称。这是弃用的功能,使用blueprints替代。

      • on_json_loading_failed(e)
      • routing_exception = None 
        如果匹配URL失败,这个异常将会/已经抛出作为请求处理的一部分。这通常用于NotFound异常或类似的情况。

      • url_rule = None 
        内部规则匹配请求的URL。这可用于在URL之前/之后检查方法是否允许(request.url_rule.methods) 等等。 
        默认情况下,在处理请求函数中写下 
        print('request.url_rule.methods', request.url_rule.methods) 
        会打印:

        request.url_rule.methods {‘GET’, ‘OPTIONS’, ‘HEAD’}

      • view_args = None 
        一个匹配请求的view参数的字典,当匹配的时候发生异常,会返回None。

  • 相关阅读:
    DotNetNuke 5 C#版本解读之1--架构介绍
    关于加入外包公司
    《深入浅出WPF》视频列表
    倒序输出字符串
    C#基础—— check、lock、using语句归纳
    Asp.net页面之间传递参数的几种方法
    sual C#中编写多线程程序之起步
    Head.First.ObjectOriented.Design.and.Analysis《深入浅出面向对象的分析与设计》读书笔记(一)
    索引分类
    表单提交中Get和Post方式的区别
  • 原文地址:https://www.cnblogs.com/Erick-L/p/6991079.html
Copyright © 2011-2022 走看看