zoukankan      html  css  js  c++  java
  • Flask高级

    关于Flask启动,和请求处理

    #关于后端服务的启动,无非就是启动实现了WSGI协议的socket
    #关于flask启动的无非就是下面两段代码
    
    #加载配置,创建Flask对象
    app = Flask(__name__)
    #这个是启动werkzeug服务
    app.run()
    
    下面我们来分析上面两段代码
    

    app.run()

    run_simple(host, port, self, **options)找到起服务的核心代码

        def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
            if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
                from .debughelpers import explain_ignored_app_run
                explain_ignored_app_run()
                return
    
            if get_load_dotenv(load_dotenv):
                cli.load_dotenv()
    
                if "FLASK_ENV" in os.environ:
                    self.env = get_env()
                    self.debug = get_debug_flag()
                elif "FLASK_DEBUG" in os.environ:
                    self.debug = get_debug_flag()
    
            if debug is not None:
                self.debug = bool(debug)
    
            _host = "127.0.0.1"
            _port = 5000
            server_name = self.config.get("SERVER_NAME")
            sn_host, sn_port = None, None
    
            if server_name:
                sn_host, _, sn_port = server_name.partition(":")
    
            host = host or sn_host or _host
            port = int(next((p for p in (port, sn_port) if p is not None), _port))
    
            options.setdefault("use_reloader", self.debug)
            options.setdefault("use_debugger", self.debug)
            options.setdefault("threaded", True)
    
            cli.show_server_banner(self.env, self.debug, self.name, False)
    
            from werkzeug.serving import run_simple
    
            try:
            #############################################
                #开启werkzeug服务
                run_simple(host, port, self, **options)
            finally:
                self._got_first_request = False
    
    
    

    请求-app.__call__()

    上面我们已经启动了wsgi服务

    run_simple(host, port, self, **options)

    当来一个请求来的时候wsgi就会执行一次self()

    当执行self()就相当于执行了app.__call__()
    

    app.__call__()

        def __call__(self, environ, start_response):
            #来一次请求就执行一次这个函数
            return self.wsgi_app(environ, start_response)
    

    wsgi_app(environ, start_response)

        #首先讲下函数的三个参数,self就是app,environ就行请求相关的数据,start_response是一个回调函数,是wsgi的用于返回一个响应行
        def wsgi_app(self, environ, start_response):
        #首先总览一下最核心的代码
        	#实例化一个ctx对象,里面封装了request和session等信息
            ctx = self.request_context(environ)
            error = None
            try:
                try:
                	#将ctx存到LOCAL对象的storage,存的格式为: storage={"执行id":{'stack':[ctx,]}}
                	#这个也就是flask的request的奇怪用法
                    ctx.push()
                    
                    #这里主要实现的是请求扩展
                    #如before_first_request,信号,和请求拓展这些函数规则的定制
                    response = self.full_dispatch_request()
                except Exception as e:
                    error = e
                    response = self.handle_exception(e)
                except:  # noqa: B001
                    error = sys.exc_info()[1]
                    raise
                #返回响应信息
                return response(environ, start_response)
            finally:
                if self.should_ignore_error(error):
                    error = None
                #删除ctx
                ctx.auto_pop(error)
    

    其他

    蓝图-flask项目架构

    蓝图的主要功能就是视图分离,不然所有视图写在一个文件会显得很杂乱

    使用三步

    1. 创建蓝图

      from flask import Blueprint
      #view
      user_bp = Blueprint('user',__name__)
      
    2. 利用蓝图创建路由关系

      #view
      @bp.route('/login/')
      def login():
      return "login"
      
    3. 注册蓝图

      #app
      app.register_blueprint(bp)
      

    注意

    使用url_for,前面要加上蓝图名

    url_for('zx.login')
    

    实例

    项目目录:

    -templates
    -static
    -views
        -user.py
        -order.py
    -app.py
    

    views/user.py

    from flask import Blueprint
    
    # 1 创建蓝图
    user_bp = Blueprint('user',__name__)
    
    # 2 利用蓝图创建路由关系
    @user_bp.route('/login/')
    def login():
        return "login"
    
    @user_bp.route('/logout/')
    def logout():
        return "logout"
    

    views/order.py

    from flask import Blueprint
    
    order_bp = Blueprint('order',__name__)
    
    @order_bp.route('/add_order/')
    def add_order():
        return "add_order"
    
    @order_bp.route('/modify_order/')
    def modify_order():
        return "modify_order"
    

    app.py

    from flask import Flask
    from views.user import user_bp
    from views.order import order_bp
    
    app = Flask(__name__)
    # 3 注册蓝图
    app.register_blueprint(user_bp)
    app.register_blueprint(order_bp)
    
    
    if __name__ == '__main__':
        app.run()
    

    g对象

    g对象使用周期是一次请求,先设置值,在取值

    from flask import g
     
     #设置值
     g.name = "zx"
     #取值
     g.name
    

    信号

    安装

    pip install blinker
    

    内置信号

    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在其中添加数据时,自动触发
    

    使用信号

    # 往信号中注册函数
    def func(*args,**kwargs):
        print('触发型号',args,kwargs)
        
    #这个是内置信号
    signals.request_started.connect(func)
    

    一个源码中的内置信号

        def full_dispatch_request(self):
            """Dispatches the request and on top of that performs request
            pre and postprocessing as well as HTTP exception catching and
            error handling.
    
            .. versionadded:: 0.7
            """
            self.try_trigger_before_first_request_functions()
            try:
            	#这里看到没有
                request_started.send(self)
                rv = self.preprocess_request()
                if rv is None:
                    rv = self.dispatch_request()
            except Exception as e:
                rv = self.handle_user_exception(e)
            return self.finalize_request(rv)
    

    自定义信号

    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()
    

    自定义session

    我们知道Django的session是存在数据库的,而flask的默认是通过cookie实现的,那我们如果想要存在数据库怎么办呢?

    安装

    pip install flask-session
    

    使用

    from flask import Flask,session
    from flask_session import RedisSessionInterface
    import redis
    app = Flask(__name__)
    
    conn=redis.Redis(host='127.0.0.1',port=6379)
    #use_signer是否对key签名,默认为false
    #key_prefix为存储的k值的前缀
    #permanent默认为True,浏览器关闭cookie失效
    app.session_interface=RedisSessionInterface(conn,key_prefix='zx')
    
    @app.route('/')
    def hello_world():
        session['name']='zx125'
        print(session['name'])
        return 'Hello World!'
    
    if __name__ == '__main__':
        app.run()
    
    

    自定义命令

    安装

    pip install flask-script
    

    使用

    from flask_script import Manager
    app = Flask(__name__)
    manager=Manager(app)
    ...
    if __name__ == '__main__':
        manager.run()
    #以后在执行,直接:python3 manage.py runserver
    #python3 manage.py runserver --help
    

    参考链接

    https://www.cnblogs.com/xiaoyuanqujing/protected/articles/11715484.html

  • 相关阅读:
    后端开发-Mybatis开发之一
    Zeppelin推荐
    构建Maven项目
    linux使用curl进行WebService接口测试
    html和jsp的区别及优缺点
    Ajax实现Web长连接
    java生成二维码
    Android调用传感器和震动
    【Head First设计模式-读书笔记】装饰者模式
    【Head First设计模式-读书笔记】观察者模式
  • 原文地址:https://www.cnblogs.com/zx125/p/12057230.html
Copyright © 2011-2022 走看看