flask

作者: 唯此 | 来源:发表于2018-09-10 13:02 被阅读0次

    如何使用flask做vue的静态文件服务器?

    原理: 让flask的静态文件与模板文件的根目录指向vue的静态文件地址.

    from flask import Flask, render_template
    def create_static_app(folder_path):
        app = Flask(__name__,
                    static_folder = folder_path,
                    template_folder= folder_path)
      
        @app.route('/', defaults={'rel_path': ''})
        @app.route('/<path:rel_path>') #解析url地址
        def path_serve(rel_path):
            if rel_path.split(".")[-1] in ["js","css","ico","ttf","woff","map"]:
                # 这些文件都从静态文夹里面获取
                return app.send_static_file(rel_path)
            elif not rel_path:
                return render_template("index.html")
            else:
                raise ("cannot deal with {}".format(rel_path))
        return app
    
    if __name__ =="__main__":
        app = create_static_app(r"D:\gdrive\js_swz\searchtest\app\dist")
        app.run(host="192.168.1.9", port=9200, debug=True)
    

    坑: flask的render_template方法会自动使用jinja2的语法来替换{{var}}.替换为空字符之后,vue再解析的时候就没有这些大括号了.最简单的处理方式是用app.send_static_file方法,这个方法不会去替换{{var}}

    如何让flask自动热加载?

    flask执行.run方法的时候,可以把debug选项改为True,这样可以热加载了.下图中我修改了main.py文件,然后flask感应到这个修改,执行了reload.


    热加载示意

    热更新的细节: 如果flask所以来的其他模块变化了,它自己会更新吗?

    如何使用flask来处理post请求?

    server端:

    @app.route('/text', methods=['POST', 'GET'])
    def convert_code():
        """
        使用reqeust.get_data()方法才能得到传进来的json
        :return:
        """
        code_text = request.get_data()
        json_data = json.loads(code_text.decode("utf-8"))
        text_content = json_data['text']
    

    web端(jinjia模板):

    let xmlhttp=new XMLHttpRequest();
    xmlhttp.open("POST","http://{{host_ip}}:5000/text",true);
    xmlhttp.send(JSON.stringify({text:t.value}));
    

    flask 如何做文件服务器

    核心是使用send_from_directory这个函数来获取指定路径上的文件.

    from flask import Flask
    from flask import request, render_template, make_response, jsonify,send_from_directory
    from run_fishsite.instance import config as instance_cf
    app = Flask(__name__)
    @app.route("/phtml/<path:rel_path>")
    def show_phtml(rel_path):
         return send_from_directory(instance_cf.phtml_dir, rel_path, as_attachment=False)  # as_attachment代码是下载还是打开
    

    上传文件会略微复杂一下,可以使用原生的flask,也可以使用插件:https://pythonhosted.org/Flask-Uploads/

    如何使用flask_login实现登录?

    实现思路: 1. 实现登录认证. 2. 实现登录状态保持. 3. 同一个url根据登录状态来返回不同结果.
    在flask_login库中登录状态是由User类的对象保持的.不同的session会有不同的User类对象. 这个插件封装了session中的设置.
    flask_login本身的函数提供了必要的操作流程,包括login_user函数, logout_user函数.
    log_manager是为了给flask_login提供扩展,可以配置不同的回调函数.包括user的id设置,未登录提示,current_user等.

    #coding=utf-8
    import flask
    import flask_login
    # ------------------------- 配置 -------------------------
    secret_key =  'super secret string'  # flask要求任何与session相关的操作都需要密钥来确保安全性.
    users = {'foo@bar.tld': {'password': 'secret'}}
    app = flask.Flask(__name__)
    app.secret_key = secret_key
    # ------------------------- 定义User -------------------------
    class User(flask_login.UserMixin): # 继承了基本的用户模型, User基本上就是一些属性的集合而已.
        pass
    
    # ------------------------- 配置login_manager-------------------------
    login_manager = flask_login.LoginManager()
    login_manager.init_app(app) # 绑定到app中去
    
    @login_manager.unauthorized_handler
    def unauthorized_handler():
        return 'Unauthorized'
    
    
    @login_manager.user_loader # 把user_loader挂载到login_manager上, 接受一个用户id作为参数,然后返回none或者user实例.
    def user_loader(email):
        print("I am user_loader")
        if email not in users:
            return
    
        user = User() # 登录成功,新建一个User实例
        user.id = email
        return user
    
    
    @login_manager.request_loader
    def request_loader(request): # 不使用cookie的登录方法,可以直接从request对象中获取登录状态;flask-login会优先检查请求的cookie,当发现用户cookie不存在的时候才会根据request来验证
        print("I am request_loader")
        email = request.form.get('email')
        if email not in users:
            return
    
        user = User()
        user.id = email
    
        # DO NOT ever store passwords in plaintext and always compare password
        # hashes using constant-time comparison!
        user.is_authenticated = request.form['password'] == users[email]['password']  # 对比密码
        return user
    # ------------------------- 使用flask_login-------------------------
    @app.route('/login', methods=['GET', 'POST']) # 绑定登录页面
    def login():
        if flask.request.method == 'GET':
            return '''
                   <form action='login' method='POST'>
                    <input type='text' name='email' id='email' placeholder='email'/>
                    <input type='password' name='password' id='password' placeholder='password'/>
                    <input type='submit' name='submit'/>
                   </form>
                   ''' # 返回输入框
    
        email = flask.request.form['email'] # 得到用户名(email)
        if flask.request.form['password'] == users[email]['password']: # 校验密码
            user = User()
            user.id = email
            flask_login.login_user(user) # 让用户登录进去, 此时会调用user_loader函数
            return flask.redirect(flask.url_for('protected')) # 登录之后的重定向到/protected, url_for是一个类似于相对路径的概念.
    
        return 'Bad login'# 密码不对
    
    
    @app.route('/protected')
    @flask_login.login_required # 需要登录
    def protected():
        return 'Logged in as: ' + flask_login.current_user.id # flask_login.current_user能够识别出当前的userid, flask_login维护一个比login_manager更上层的状态
    
    @app.route('/logout')
    def logout():
        flask_login.logout_user()
        return 'Logged out'
    # ------------------------- 运行app-------------------------
    app.run(host="192.168.1.4", port=5004, debug= True)
    

    如何处理报错?

    @app.errorhandler(401)
    def page_not_found(e):
        return Response('<p>Login failed</p>')
    

    静态文件夹与路由的冲突

    如果设置了静态文件夹,flask会自动根据url的地址来去静态文件中获取相应的文件.这样就忽略了用户自定义的路由函数.

    app = Flask(__name__, static_folder=r"\\192.168.1.9\searchtest\app\static")
    @app.route('/', defaults={'rel_path': ''})
    @app.route('/path:rel_path>')
    def path_serve(rel_path):
    # mycode
    

    此时所有get \static***这样的请求都会去静态文件夹中去找相应的文件.而忽略掉path_server

    端口冲突的坑

    某些端口能够启动flask,但是请求就是发不到flask上去.=>需要提前检查端口占用,被占用了就报错.

    路由不识别根目录

    @app.route("/dataeditor/<path:rel_path>")使用这样的路由会导致dataedtor这个根目录无响应.
    坑: 默认的模板路径为templates而不是template

    flask的自动多线程

    使用了aiohttp这个异步请求的方法可以探知到flask自带多线程执行的.
    案例1: 在view函数中,使用time.sleep(1), 然后连续发起两个请求,总耗时1.01秒左右.
    案例2: 在view函数中使用全局变量,也不影响flask的时间消耗.

    cout = [1]
        @app.route("/")
        def home():
            html_str = """
            cout[0] = cout[0] + 1
            print(cout[0])
            time.sleep(1)
            # return html_str
            return str(cout)
    

    但是,如果调用了一个堵塞的io接口,那么会阻塞flask多线程的执行.例如tdx的交易接口.此时可以开启另一个tdx连接实例来降低延时.

    坑: reqeust一般需要在view函数才可以引用.

    flask多线程,可以使用 flask.copy_current_request_context这个装饰器,来获取当前的request中的信息.

    参考:http://flask.pocoo.org/docs/1.0/api/#flask.copy_current_request_context

    可以使用celery来实现后台进程,来不断地update数据.
    http://flask.pocoo.org/docs/1.0/patterns/celery/

    如何传递列表给flask

    res = requests.get("http://192.168.1.4:5004/try_list", json=[1,3,4]) # 在flask 那边需要使用request.get_json来解析出列表来

    坑: post请求被识别为get请求

    如果post后面不加反斜杠的话,会被认为是get请求

    requests.post(192.168.1.4:5000/ymarket, data=a_dict) # flask端会认为是get请求
    

    坑: 在pycharm中启动flask

    在pycharm中执行flask程序,会自动忽略app.run命令.因此需要在配置中配置好host与port


    image.png

    1

    相关文章

      网友评论

          本文标题:flask

          本文链接:https://www.haomeiwen.com/subject/sfjliftx.html