zoukankan      html  css  js  c++  java
  • WEB框架之Flask

    WEB框架之Flask

     

    Django:1个重武器,包含了web开发中常用的功能、组件的框架;(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....);

    Tornado:2大特性就是异步非阻塞、原生支持WebSocket协议;

    Flask:功能和性能虽然不及Django和Tornado,但是Flask的第三方开源组件比丰富;http://flask.pocoo.org/extensions/

    Bottle:比较简单;

    总结:

    都不是我写的!!!不论优劣,不同的工具而已;

    小型web应用设计的功能点不多使用Flask;

    大型web应用设计的功能点比较多使用的组件也会比较多,使用Django(自带功能多不用去找插件);

    如果追求性能可以考虑Tornado;

    Flask的socket是基于Werkzeug 实现的,模板语言依赖jinja2模板,在使用Flask之前需要安装一下;

    pip3 install flask           #安装flask
    from werkzeug.wrappers import Request, Response  # Flask的socket使用werkzeug实现,所以要导入 werkzeug
    
    @Request.application
    
    def hellow(request):
        return Response('Hello World')
    
    if __name__ == '__main__':
        from werkzeug.serving import run_simple
        run_simple('localhost',400,hellow)
    werkzeug

    Flask简单使用

    from flask import Flask
    
    app=Flask(__name__) #创建1个Flask实例
    
    @app.route('/')      #路由系统生成 视图对应url,1. decorator=app.route() 2. decorator(first_flask)
    def first_flask():    #视图函数
        return 'Hello World'  #response
    
    
    if __name__ == '__main__':
        app.run()              #启动socket
    View Code

    一、配置文件

    app=Flask(__name__,template_folder='templates',static_url_path='/static/',static_path='/zhanggen')

    模板路径: template_folder='templates'

    静态文件路径:static_url_path='/static/'

    静态文件引入别名:static_path='/zhanggen'

    设置为调试环境:app.debug=True (代码修改自动更新)

    设置json编码格式 如果为False 就不使用ascii编码:app.config['JSON_AS_ASCII']=False 

    设置响应头信息Content-Type   app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8"  (注意 ;charset=utf-8)

    二、路由系统

    1.动态路由(url传参)

    @app.route('/user/<name>')

    from flask import Flask
    
    app=Flask(__name__)
    
    @app.route('/<name>')  #设置url传参数 http://127.0.0.1:5000/zhanggen
    def first_flask(name):  #视图必须有对应接收参数
        print(name)
        return 'Hello World'  #response
    
    
    if __name__ == '__main__':
        app.run()
    接收字符串类型参数

    @app.route('/post/<int:age>')

    #接收整型数字参数
    app=Flask(__name__)
    @app.route('/<int:age>/')  #设置url传参数 http://127.0.0.1:5000/18/
    def first_flask(age):  #视图必须有对应接收参数
        print(age)
        return 'Hello World'  #response
    
    if __name__ == '__main__':
        app.run()
    接收整型数字参数

    @app.route('/post/<float:salary>')

    #接收浮点型型数字参数
    app=Flask(__name__)
    @app.route('/<float:salary>/')  #设置url传参数http://127.0.0.1:5000/2345555.8889/
    def first_flask(salary):  #视图必须有对应接收参数
        print(salary)
        return 'Hello World'  #response
    
    if __name__ == '__main__':
        app.run()
    接收浮点型数字参数

    @app.route('/post/<path:path>')

    # 接收URL链接类型参数
    app=Flask(__name__)
    @app.route('/<path:url>/')  #设置url传参数:http://127.0.0.1:5000/http://www.baiu.com/
    def first_flask(url):  #视图必须有对应接收参数
        print(url)
        return 'Hello World'  #response
    
    if __name__ == '__main__':
        app.run()
    接收URL链接类型参数

    2、指定允许的请求方法

    @app.route('/login', methods=['GET', 'POST']) 

    # 指定允许的请求方法
    app=Flask(__name__)
    @app.route('/<path:url>/',methods=['get']) #只允许get请求
    def first_flask(url):
        print(url)
        return 'Hello World'  #response
    
    if __name__ == '__main__':
        app.run()
    指定允许的请求方法

    3、通过别名反向生成url

    #反向生成url
    from flask import Flask,url_for
    app=Flask(__name__)
    @app.route('/<path:url>',endpoint='name1')
    def first_flask(url):
        print(url_for('name1',url=url)) #如果设置了url参数,url_for(别名,加参数)
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()
    url_for()反向生成url

    4、通过app.add_url_rule()调用路由

    #方式2通过app.add_url_rule()方法的方式调用路由
    app=Flask(__name__)
    
    def first_flask():
        return 'Hello World' 
    
    app.add_url_rule(rule='/index/',endpoint='name1',view_func=first_flask,methods=['GET'])
    #app.add_url_rule(rule=访问的url,endpoint=路由别名,view_func=视图名称,methods=[允许访问的方法])
    if __name__ == '__main__':
        app.run()
    app.add_url_rule()方法调用路由

    5、扩展路由功能:正则匹配url

    如果需要一些复杂的匹配规则可以自定义正则匹配url

        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()
    自定义正则表达式匹配路由

    四、视图

    1、给Flask视图函数加装饰器

    注意如果要给视图函数加装饰器增加新功能,一点要加在路由装饰器下面,才会被路由装饰器装饰,才能生生成url关系;

    #给Flask视图加装饰器
    #1、定义1个装饰器
    
    def auth(func):
        print('我在上面')
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    
    app=Flask(__name__)
    
    @app.route('/',methods=['GET'])
    @auth #注意如果要给视图函数加装饰器,一点要加在路由装饰器下面,才会被路由装饰器装饰
    def first_flask():
        print('ffff')
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()
    View Code

    2、request和response

     a.请求相关信息

    request.method: 获取请求方法

    request.json

    request.json.get("json_key"):获取json数据 **较常用      

    request.argsget('name') :获取get请求参数   

    request.form.get('name') :获取POST请求参数

    request.form.getlist('name_list'):获取POST请求参数列表(多个)

    request.values.get('age') :获取GET和POST请求携带的所有参数(GET/POST通用)

    request.cookies.get('name'):获取cookies信息

    request.headers.get('Host'):获取请求头相关信息

    request.path:获取用户访问的url地址,例如(/,/login/,/ index/);

    request.full_path:获取用户访问的完整url地址+参数 例如(/login/?age=18)

    request.script_root: 抱歉,暂未理解其含义;

    request.url:获取访问url地址,例如http://127.0.0.1:5000/?age=18;

    request.base_url:获取访问url地址,例如 http://127.0.0.1:5000/;

    request.url_root

    request.host_url

    request.host:获取主机地址

    request.files:获取用户上传的文件

    obj = request.files['the_file_name']

    obj.save('/var/www/uploads/' + secure_filename(f.filename))  直接保存

     

     b、响应相关信息

    return "字符串" :响应字符串

    return render_template('html模板路径',**{}):响应模板

    return redirect('/index.html'):跳转页面

    响应json数据

    方式1: return jsonify(user_list) 

    app.config['JSON_AS_ASCII']=False  #指定json编码格式 如果为False 就不使用ascii编码,
    app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" #指定浏览器渲染的文件类型,和解码格式;
    配置

    方式2:

    return Response(data,mimetype="application/json;charset=utf-8",)

    如果需要设置响应头就需要借助make_response()方法

    from flask import Flask,request,make_response           

    response = make_response(render_template('index.html'))

    response是flask.wrappers.Response类型

    response.delete_cookie('key')

    response.set_cookie('key', 'value')

    response.headers['X-Something'] = 'A value'

    return respons

    3 、Flask之CBV视图

    #CBV视图
    from flask import Flask,url_for,views
    #-----------------------------------------------------
    app=Flask(__name__)               #装饰器
    
    def auth(func):
        print('我在上面')
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    #--------------------------------------------------------
    class IndexView(views.MethodView):  #CBV视图
        methods=['GET']                #允许的http请求方法(改CBV只允许GET方法)
        decorators = [auth,]            #每次请求过来都加auth装饰器
    
        def get(self):
            return 'Index.GET'
        def post(self):
            return 'Index.POST'
    
    app.add_url_rule('/index/',view_func=IndexView.as_view(name='name1')) #(name='name1'反向生成url别名
    
    
    if __name__ == '__main__':
        app.run()
    CBV视图

     

    五、模板语言

    Flask使用的是Jinja2模板,所以其语法和Django无差别(Django的模板语言参考Jinja2)

    1.引用静态文件

    方式1:别名引入

    <link rel="stylesheet" href="/zhanggen/commons.css">

    方式2:url_for()方法引入

    <link rel="stylesheet" href="{{  url_for('static',filename='commons.css')  }}">

    2.模板语言引用上下文对象

    变量

    <h1>{{user_list}}</h1> <!--变量 -->
    View Code

    循环、索引取值

    <ul>
    {% for user in user_list %}   <!--循环 -->
        <li>{{user}}</li>
    {% endfor %}
    
    {{user_list.0}}             <!-- 索引取值-->
    
    </ul>
    View Code

    Flask的Jinjia2可以通过Context 把视图中的函数传递把模板语言中执行,这就是Django中的simple_tag和simple_fifter;

    simple_tag(只能传2个参数,支持for、if)

    @app.template_global()   #simple_tag
    def foo(arg):
        return '<input type="text">'
    视图
    <h1>{{foo(1)|safe}}</h1>                   <!--Flask的模板语言支持simple_tag-->
    模板语言

    simple_fifter(对参数个数无限制,不支持for、if)

    @app.template_filter()  #simple_fifter
    def foo1(arg1,arg2,arg3):
        return arg1+arg2+arg3
    视图
    <h1> {{ 'alex'|foo1('s ','b',) }}  </h1>     <!-- simple_fifter -->
    模板语言

    六、session功能

    1. Flask自带的session功能

    from flask import session
    import json
    app=Flask(__name__,template_folder='templates',static_path='/static/',static_url_path='/static/')
    app.debug=True
    app.secret_key='sjehfjeefrjewth43u'  #设置session加密
    app.config['JSON_AS_ASCII']=False  #指定json编码格式 如果为False 就不使用ascii编码,
    app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" #指定浏览器渲染的文件类型,和解码格式;
    
    @app.route('/login/',methods=['GET','POST'])
    def login():
        msg = ''
        if request.method=='POST':
            name=request.values.get('user')
            pwd=request.values.get('pwd')
            if name =='zhanggen' and pwd=='123.com':
                session['user']=name  #设置session的key value
                return redirect('/index/')
            else:
                msg='用户名或者密码错误'
        return render_template('login.html',msg=msg)
    
    @app.route('/index/',methods=['GET','POST'])
    def index():
        user_list = ['张根', 'egon', 'eric']
        user=session.get('user')           #获取session
        if user:
            user=['alex','egon','eric']
            return jsonify(user_list)
        else:
            return redirect('/login/')
    
    if __name__ == '__main__':
        app.run()
    Flask自带session功能

    2.第三方session组件(Session)

    安装 pip install flask-session

    from flask import session, Flask,request,make_response,render_template,redirect,jsonify,Response
    
    from flask.ext.session import Session #引入第三方session
    import json
    app=Flask(__name__,template_folder='templates',static_path='/static/',static_url_path='/static/')
    app.debug=True
    app.secret_key='sjehfjeefrjewth43u'  #设置session加密
    app.config['JSON_AS_ASCII']=False  #指定json编码格式 如果为False 就不使用ascii编码,
    app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" #指定浏览器渲染的文件类型,和解码格式;
    
    app.config['SESSION_TYPE']='redis'
    
    from redis import Redis        #引入连接 redis模块
    app.config['SESSION_REDIS']=Redis(host='192.168.0.94',port=6379) #连接redis
    Session(app)
    
    @app.route('/login/',methods=['GET','POST'])
    def login():
        msg = ''
        if request.method=='POST':
            name=request.values.get('user')
            pwd=request.values.get('pwd')
            if name =='zhanggen' and pwd=='123.com':
                session['user']=name  #设置session的key value
                return redirect('/index/')
            else:
                msg='用户名或者密码错误'
        return render_template('login.html',msg=msg)
    
    @app.route('/index/',methods=['GET','POST'])
    def index():
        user_list = ['张根', 'egon', 'eric']
        user=session.get('user')           #获取session
        if user:
            user=['alex','egon','eric']
            return jsonify(user_list)
        else:
            return redirect('/login/')
    
    if __name__ == '__main__':
        app.run()
    把session存到redis

    不仅可以把session存放到redis还可放到文件、内存、memcache...

        def _get_interface(self, app):
            config = app.config.copy()
            config.setdefault('SESSION_TYPE', 'null')
            config.setdefault('SESSION_PERMANENT', True)
            config.setdefault('SESSION_USE_SIGNER', False)
            config.setdefault('SESSION_KEY_PREFIX', 'session:')
            config.setdefault('SESSION_REDIS', None)
            config.setdefault('SESSION_MEMCACHED', None)
            config.setdefault('SESSION_FILE_DIR',
                              os.path.join(os.getcwd(), 'flask_session'))
            config.setdefault('SESSION_FILE_THRESHOLD', 500)
            config.setdefault('SESSION_FILE_MODE', 384)
            config.setdefault('SESSION_MONGODB', None)
            config.setdefault('SESSION_MONGODB_DB', 'flask_session')
            config.setdefault('SESSION_MONGODB_COLLECT', 'sessions')
            config.setdefault('SESSION_SQLALCHEMY', None)
            config.setdefault('SESSION_SQLALCHEMY_TABLE', 'sessions')
    
            if config['SESSION_TYPE'] == 'redis':
                session_interface = RedisSessionInterface(
                    config['SESSION_REDIS'], config['SESSION_KEY_PREFIX'],
                    config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'memcached':
                session_interface = MemcachedSessionInterface(
                    config['SESSION_MEMCACHED'], config['SESSION_KEY_PREFIX'],
                    config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'filesystem':
                session_interface = FileSystemSessionInterface(
                    config['SESSION_FILE_DIR'], config['SESSION_FILE_THRESHOLD'],
                    config['SESSION_FILE_MODE'], config['SESSION_KEY_PREFIX'],
                    config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'mongodb':
                session_interface = MongoDBSessionInterface(
                    config['SESSION_MONGODB'], config['SESSION_MONGODB_DB'],
                    config['SESSION_MONGODB_COLLECT'],
                    config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
                    config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'sqlalchemy':
                session_interface = SqlAlchemySessionInterface(
                    app, config['SESSION_SQLALCHEMY'],
                    config['SESSION_SQLALCHEMY_TABLE'],
                    config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
                    config['SESSION_PERMANENT'])
            else:
                session_interface = NullSessionInterface()
    
            return session_interface
    View Code

    3.自定义session组件

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import uuid
    import json
    from flask.sessions import SessionInterface
    from flask.sessions import SessionMixin
    from itsdangerous import Signer, BadSignature, want_bytes
    
    
    class MySession(dict, SessionMixin):
        def __init__(self, initial=None, sid=None):
            self.sid = sid
            self.initial = initial
            super(MySession, self).__init__(initial or ())
    
        def __setitem__(self, key, value):
            super(MySession, self).__setitem__(key, value)
    
        def __getitem__(self, item):
            return super(MySession, self).__getitem__(item)
    
        def __delitem__(self, key):
            super(MySession, self).__delitem__(key)
    
    
    class MySessionInterface(SessionInterface):
        session_class = MySession
        container = {}
    
        def __init__(self):
            import redis
            self.redis = redis.Redis()
    
        def _generate_sid(self):
            return str(uuid.uuid4())
    
        def _get_signer(self, app):
            if not app.secret_key:
                return None
            return Signer(app.secret_key, salt='flask-session',
                          key_derivation='hmac')
    
        def open_session(self, app, request):
            """
            程序刚启动时执行,需要返回一个session对象
            """
            sid = request.cookies.get(app.session_cookie_name)
            if not sid:
                sid = self._generate_sid()
                return self.session_class(sid=sid)
    
            signer = self._get_signer(app)
            try:
                sid_as_bytes = signer.unsign(sid)
                sid = sid_as_bytes.decode()
            except BadSignature:
                sid = self._generate_sid()
                return self.session_class(sid=sid)
    
            # session保存在redis中
            # val = self.redis.get(sid)
            # session保存在内存中
            val = self.container.get(sid)
    
            if val is not None:
                try:
                    data = json.loads(val)
                    return self.session_class(data, sid=sid)
                except:
                    return self.session_class(sid=sid)
            return self.session_class(sid=sid)
    
        def save_session(self, app, session, response):
            """
            程序结束前执行,可以保存session中所有的值
            如:
                保存到resit
                写入到用户cookie
            """
            domain = self.get_cookie_domain(app)
            path = self.get_cookie_path(app)
            httponly = self.get_cookie_httponly(app)
            secure = self.get_cookie_secure(app)
            expires = self.get_expiration_time(app, session)
    
            val = json.dumps(dict(session))
    
            # session保存在redis中
            # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)
            # session保存在内存中
            self.container.setdefault(session.sid, val)
    
            session_id = self._get_signer(app).sign(want_bytes(session.sid))
    
            response.set_cookie(app.session_cookie_name, session_id,
                                expires=expires, httponly=httponly,
                                domain=domain, path=path, secure=secure)
    组件
    from flask import Flask
    from flask import session
    from my_session import MySessionInterface
    
    app = Flask(__name__)
    
    app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
    app.session_interface = MySessionInterface()
    
    
    @app.route('/login/', methods=['GET', "POST"])
    def login():
        print(session)
        session['user1'] = 'alex'
        session['user2'] = 'alex'
        del session['user2']
    
        return "内容"
    
    
    if __name__ == '__main__':
        app.run()
    应用

     七、蓝图

    使用Flask自带Blueprintmuk模块,帮助我们做代码目录结构的归类

    import luffy   #导入luffy包就会执行luffy包中__init__.py文件
    
    luffy.app.run()
    app.py
    from flask import Flask
    
    app=Flask(__name__,template_folder='templates',static_path='/static/',static_url_path='/static/')
    
    app.debug=True
    
    
    from .views import login
    from .views import index
    
    #把文件中蓝图对象注册到app里
    app.register_blueprint(login.login,url_prefix='/login') #访问login蓝图必须以url_prefix开头
    app.register_blueprint(index.index,url_prefix='/index')
    
    if __name__ == '__main__':
        app.run()
    luffy包的__init__.py
    from flask import Blueprint     #导入蓝图
    login=Blueprint('login',__name__) #在本模块实例化1个蓝图
    
    @login.route('/login/',methods=['GET','POST'])
    def login1():
        return '登录页面'
    login
    from flask import Blueprint
    index=Blueprint('index',__name__)
    @index.route('/index/',methods=['GET','POST'])
    def index1():
        return '首页'
    index

     

    八、message (闪现)

    message是一个基于Session实现的用于保存数据的集合,其特点是:一次性。

    特点:和labada匿名函数一样不长期占用内存

    from flask import Flask,request,flash,get_flashed_messages
    
    app = Flask(__name__)
    app.secret_key = 'some_secret'
    
    
    @app.route('/set/')
    def index2():
        flash('Disposable')    #在message中设置1个个值
        return 'ok'
    
    #---------------------------------------------------------------------------------
    
    @app.route('/')
    def index1():
        messages = get_flashed_messages() #获取message中设置的值,只能获取1次。(1次性)
        print(messages)
        return "Index1"
    
    
    
    
    
    
    if __name__ == "__main__":
        app.run()
    flask_message

    九、中间件

    flask也有中间件功能和Django类似,不同的是使用的是使用3个装饰器来实现的;

    1.@app.before_first_request :请求第1次到来执行1次,之后都不执行;

    2.@app.before_request:请求到达视图之前执行;(改函数不能有返回值,否则直接在当前返回)

    3.@app.after_request:请求 经过视图之后执行;(最下面的先执行)

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from flask import Flask, Request, render_template
    
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    @app.before_first_request  #第1个请求到来执行
    def before_first_request1():
        print('before_first_request1')
    
    
    @app.before_request #中间件2
    def before_request1():
        Request.nnn = 123
        print('before_request1')  #不能有返回值,一旦有返回值在当前返回
    
    
    @app.before_request
    def before_request2():
        print('before_request2')
    
    
    
    @app.errorhandler(404)
    def page_not_found(error):
        return 'This page does not exist', 404
    
    
    
    @app.route('/')
    def hello_world():
        return "Hello World"
    
    
    
    
    
    @app.after_request #中间件 执行视图之后
    def after_request1(response):
        print('after_request1', response)
        return response
    
    
    @app.after_request #中间件 执行视图之后 先执行 after_request2
    def after_request2(response):
        print('after_request2', response)
        return response
    
    if __name__ == '__main__':
        app.run()
    View Code

     

    十、Flask插件

    WTForms    

    SQLAchemy

    等...    详细见:http://flask.pocoo.org/extensions/

    文档:http://docs.jinkan.org/docs/flask/quickstart.html

     
     
     
     
     
  • 相关阅读:
    Project 01 PlantAndZomb
    iOS平台内存使用原则
    IOS之UIKit_Day22--23
    IOS之UIKit_Day21
    IOS之UIKit_Day20
    浅谈javascript数据类型,对象,类
    从输入一个url到加载页面发生了什么?
    d3.js(2)-svg
    d3.js(1)
    console.time和performance.now()
  • 原文地址:https://www.cnblogs.com/taosiyu/p/11371419.html
Copyright © 2011-2022 走看看