码迷,mamicode.com
首页 > Web开发 > 详细

WEB框架之Flask

时间:2019-08-18 10:00:20      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:ane   handler   system   only   lis   gpo   lin   table   jee   

 

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

 
 

WEB框架之Flask

标签:ane   handler   system   only   lis   gpo   lin   table   jee   

原文地址:https://www.cnblogs.com/taosiyu/p/11371419.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!