Flask是一个基于 Python 开发并且依赖 jinja2 模板和 Werkzeug WSGI 服务的一个微型框架,对于 Werkzeug 本质是 Socket 服务端,其用于接收 http 请求并对请求进行预处理,然后触发 Flask 框架,开发人员基于 Flask 框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助 jinja2 模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

准备

安装

pip3 install flask

werkzeug的简单使用

from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple @Request.application
def hello(request):
return Response('Hello World!') if __name__ == '__main__':
run_simple('localhost', 4000, hello)

使用

hello flask

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello World!' if __name__ == '__main__':
app.run()

登录示例

from flask import Flask, request, render_template, redirect, session

app = Flask(__name__,
template_folder='templates', # 默认模板文件夹
static_folder='static', # 默认静态文件文件夹
static_url_path='/static' # 默认静态文件访问路径
)
app.config['DEBUG'] = True
# 使用 session 必须定义 否则报错
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' # 默认只支持 GET 请求
@app.route('/login', methods=['GET', "POST"])
def login():
if request.method == 'GET':
# 渲染模板 默认对应templates 文件夹
return render_template('login.html')
user = request.form.get('user')
pwd = request.form.get('pwd') if user == 'zze' and pwd == '':
session['user'] = user
# 重定向
return redirect('/index')
return render_template('login.html', msg='用户名或密码错误!') @app.route('/index')
def index():
user = session['user']
if not user:
return redirect('/login')
return render_template('index.html') if __name__ == '__main__':
app.run()

配置文件

  • 方式一:app.config

    app.config 本质上其实是一个字典,所以可以通过如下方式进行配置:

    from flask import Flask
    
    app = Flask(__name__)
    app.config['DEBUG'] = True
  • 方式二:对象配置

    当然,Flask 也提供了单文件配置的方式,如下:

    class Dev:
    DEBUG = True

    settings.py

    from flask import Flask
    
    app = Flask(__name__)
    app.config.from_object('settings.Dev')
  • 方式三:文件配置

    app.config.from_pyfile("settings.py")
    # 如:
    # settings.py
    # DEBUG = True
  • 方式四:环境变量

    app.config.from_envvar("环境变量名称")
    # 环境变量的值为python文件名称名称,内部调用from_pyfile方法
  • 方式五:json方式

    app.config.from_json("json文件名称")
    # json文件名称,必须是json格式,因为内部会执行json.loads
  • 方式六:字典方式

    app.config.from_mapping({'DEBUG':True})
    # 字典格式
  • 默认配置参数

    {
    'DEBUG': get_debug_flag(default=False), 是否开启Debug模式
    'TESTING': False, 是否开启测试模式
    'PROPAGATE_EXCEPTIONS': None,
    'PRESERVE_CONTEXT_ON_EXCEPTION': None,
    'SECRET_KEY': None,
    'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
    'USE_X_SENDFILE': False,
    'LOGGER_NAME': None,
    'LOGGER_HANDLER_POLICY': 'always',
    'SERVER_NAME': None,
    'APPLICATION_ROOT': None,
    'SESSION_COOKIE_NAME': 'session',
    'SESSION_COOKIE_DOMAIN': None,
    'SESSION_COOKIE_PATH': None,
    'SESSION_COOKIE_HTTPONLY': True,
    'SESSION_COOKIE_SECURE': False,
    'SESSION_REFRESH_EACH_REQUEST': True,
    'MAX_CONTENT_LENGTH': None,
    'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
    'TRAP_BAD_REQUEST_ERRORS': False,
    'TRAP_HTTP_EXCEPTIONS': False,
    'EXPLAIN_TEMPLATE_LOADING': False,
    'PREFERRED_URL_SCHEME': 'http',
    'JSON_AS_ASCII': True,
    'JSON_SORT_KEYS': True,
    'JSONIFY_PRETTYPRINT_REGULAR': True,
    'JSONIFY_MIMETYPE': 'application/json',
    'TEMPLATES_AUTO_RELOAD': None,
    }

路由系统

@app.route('/user/<username>')
@app.route('/post/<int:post_id>')
@app.route('/post/<float:post_id>')
@app.route('/post/<path:path>')
@app.route('/login', methods=['GET', 'POST'])

常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:

DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}

可以通过 endpoint 和 url_for 反向生成:

from flask import Flask, url_for

app = Flask(__name__)

@app.route('/index', endpoint='i')
def index():
return url_for('i') # endpoint 值未指定时,默认为方法名 if __name__ == '__main__':
app.run()

模板

  • 语法

    Flask 使用的是 Jinjia2 模板,所以其语法和在 Django 中使用时无差别。

    Markup 等价 django 的 mark_safe。

  • 模板方法

    {% macro input(name, type='text', value='') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %} {{ input('n1') }}

请求和响应

  • 请求相关

    request 内置属性:
    request.method # 方法
    request.args # GET 请求时的参数
    request.form # POST 请求时的参数
    request.values # 所有参数
    request.cookies # cookie 内容
    request.headers # 请求头信息
    request.path # 请求路径
    request.full_path # 请求全路径 路径相关:
    request.script_root
    request.url
    request.base_url
    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))
  • 响应相关

    # 返回字符串
    return "字符串"
    # 返回渲染模板
    return render_template('html模板路径',**{})
    # 重定向
    return redirect('/index.html')

Session

当请求刚到来时,flask 读取 cookie 中 session 对应的值,并将该值解密并反序列化成字典,放入内存以便视图函数使用。

当请求结束时,flask 会读取内存中字典的值,进行序列化和加密,再写入到 cookie 中。

中间件

从 flask 的入口 app.run 方法看起,

 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 set, let env vars override previous values
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(port or sn_port or _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:
run_simple(host, port, self, **options)
finally:
self._got_first_request = False

flask.app.Flask.run

直接看到 41 行,这里的 run_simple 方法实际上就是 werkzeug.serving.run_simple ,而传入的第三个参数 self 实际上就是指的 app 本身。我们先要了解的是,在上面的werkzeug的简单使用中,传入的是一个方法,并且这个方法会在请求到来时被执行。而在这里传入一个对象,加 () 执行一个对象时实际上是执行这个对象的 __call__ 方法,查看 app.__call__ 方法:

 def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)

flask.app.Flask.__call__

看到这里我们可以确定,后续整个程序的执行就是依赖这第 2 行的触发,而我们只要在第二行执行之前定义的处理就相当于中间件的前置处理,在它之后的处理就相当于后置处理了。所以可以通过如下方法实现中间件的功能:

from flask import Flask
app = Flask(__name__) class MiddleWare:
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app def __call__(self, *args, **kwargs):
print('前置处理')
obj = self.wsgi_app(*args, **kwargs)
print('后置处理') if __name__ == "__main__":
app.wsgi_app = MiddleWare(app.wsgi_app)
app.run(port=9999)

flash

flash 就是用来存储只使用一次的数据,类似于将数据放入列表,然后通过 pop 方法取出。

flash(message, category='message')
get_flashed_messages(with_categories=False, category_filter=[])
  • 使用

    from flask import Flask, flash, get_flashed_messages
    
    app = Flask(__name__)
    
    @app.route('/page1')
    def page1():
    flash('临时数据')
    return 'page1' @app.route('/page2')
    def page2():
    get_flashed_messages()
    return 'page2' if __name__ == '__main__':
    app.run()
  • 源码分析

    查看 flash 方法:

     def flash(message, category='message'):
    flashes = session.get('_flashes', [])
    flashes.append((category, message))
    session['_flashes'] = flashes
    message_flashed.send(current_app._get_current_object(),
    message=message, category=category)

    flask.helpers.flash

    可以看到它其实就是把 message 和 category 以元组的形式存储在 session 中键为 _flashes 的值中。

    再看 get_flashed_messages 方法:

     def get_flashed_messages(with_categories=False, category_filter=[]):
    flashes = _request_ctx_stack.top.flashes
    if flashes is None:
    _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \
    if '_flashes' in session else []
    if category_filter:
    flashes = list(filter(lambda f: f[0] in category_filter, flashes))
    if not with_categories:
    return [x[1] for x in flashes]
    return flashes

    flask.helpers.get_flashed_messages

    从第 4 行可以看到每次获取 flash 数据时,就是从 session 中将之前存入的键为 _flashes 的元素 pop 出来,然后进行过滤返回对应 category 内容。

特殊的装饰器

  • before_request&after_request

    from flask import Flask, flash, get_flashed_messages
    
    app = Flask(__name__)
    app.secret_key = '' @app.before_request
    def before_request1():
    print('before_request1') @app.before_request
    def before_request2():
    print('before_request2') @app.after_request
    def after_request1(response):
    print('after_request1')
    return response @app.after_request
    def after_request2(response):
    print('after_request2')
    return response @app.route('/index')
    def index():
    print('index')
    return 'index' if __name__ == '__main__':
    app.run() # 执行顺序如下:
    # before_request1
    # before_request2
    # index
    # after_request2
    # after_request1
  • template_filter

    from flask import Flask, flash, get_flashed_messages, render_template
    
    app = Flask(__name__)
    app.secret_key = '' @app.template_filter()
    def add_filter(a, b):
    return a + b @app.route('/index')
    def index():
    print('index')
    return render_template('index.html') if __name__ == '__main__':
    app.run()
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    {{1|add_filter(2)}}
    </body>
    </html>
  • template_global

    from flask import Flask, flash, get_flashed_messages, render_template
    
    app = Flask(__name__)
    app.secret_key = '' @app.template_global()
    def add_template_func(a, b):
    return a + b @app.route('/index')
    def index():
    print('index')
    return render_template('index.html') if __name__ == '__main__':
    app.run()
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    {{add_template_func(1,2)}}
    </body>
    </html>
  • errorhandler

    @app.errorhandler(404)
    def page_not_found(error):
    return render_template('404.html'),404
  • before_first_request

    @app.before_first_request
    def application_start():
    # 同 before_request,但仅在第一次请求时执行一次。
    pass

python框架之Flask(1)-Flask初使用的更多相关文章

  1. Python框架学习之用Flask创建一个简单项目

    在前面一篇讲了如何创建一个虚拟环境,今天这一篇就来说说如何创建一个简单的Flask项目.关于Flask的具体介绍就不详细叙述了,我们只要知道它非常简洁.灵活和扩展性强就够了.它不像Django那样集成 ...

  2. [ 转载 ] Python Web 框架:Django、Flask 与 Tornado 的性能对比

    本文的数据涉及到我面试时遇到过的问题,大概一次 http 请求到收到响应需要多少时间.这个问题在实际工作中与框架有比较大的关系,因此特别就框架的性能做了一次分析. 这里使用 2016 年 6 月 9 ...

  3. Python框架 Flask 项目实战教程

    本文目的是为了完成一个项目用到的flask基本知识,例子会逐渐加深.最好对着源码,一步一步走.下载源码,运行pip install -r requirements.txt 建立环境python db_ ...

  4. Python框架学习之Flask中的常用扩展包

    Flask框架是一个扩展性非常强的框架,所以导致它有非常多的扩展包.这些扩展包的功能都很强大.本节主要汇总一些常用的扩展包. 一. Flask-Script pip install flask-scr ...

  5. Python框架学习之Flask中的蓝图与单元测试

    因为Flask框架的集成度很低,随着Flask项目文件的增多,会导致不太好管理.但如果对一个项目进行模块化管理的,那样子管理起来就会特别方便.而在Flask中刚好就提供了这么一个特别好用的工具蓝图(B ...

  6. Python框架学习之Flask中的视图及路由

    在前面一讲中我们学习如何创建一个简单的Flask项目,并做了一些简单的分析.接下来在这一节中就主要来讲讲Flask中最核心的内容之一:Werkzeug工具箱.Werkzeug是一个遵循WSGI协议的P ...

  7. python web框架(bottle,flask,tornado)

    Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Python的标准库外,其不依赖任何其他模块. pip i ...

  8. 选择一个 Python Web 框架:Django vs Flask vs Pyramid

    Pyramid, Django, 和 Flask都是优秀的框架,为项目选择其中的哪一个都是伤脑筋的事.我们将会用三种框架实现相同功能的应用来更容易的对比三者.也可以直接跳到框架实战(Framework ...

  9. python框架之Flask基础篇(二)-------- 数据库的操作

    1.flask连接数据库的四步: 倒入第三方数据库扩展包:from flask_sqlalchemy import SQLAlchemy 配置config属性,连接数据库: app.config[&q ...

随机推荐

  1. GitHubPage博客搭建学习专栏

    Hexo NexT 博客本地搭建指南 Hexo NexT 博客与Github page 关联指南 Hexo NexT 博客后台管理指南

  2. Atitit 管理的模式扁平化管理 金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理

    Atitit 管理的模式扁平化管理  金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理 1.1. 矩阵管理 1 1.2. 相关信息 矩阵的历史 1 1.3. 基于“ ...

  3. 通过itools安装ipa时,如果装不上提示"Mismatche...onIdentifierEntitlement"

    最后安装ipa时,如果装不上提示"Mismatche...onIdentifierEntitlement",一定要卸载设备里的现有的微信app!!!!!!!!!!!!!还有就是,如 ...

  4. 如何用cmd命令递归文件夹中的所有特定文件,拷贝到另一个文件夹中

    现在有一个文件夹,里面有很多子文件夹,每个子文件夹中有很多不同类型的图片,现在想将其所有.png图片整理出来,一开始我是手动拷贝的,拷贝了几个图片后,突然想能不能让计算机来自动完成此项功能,经过一番尝 ...

  5. C语言 · 超级玛丽

    算法提高 超级玛丽   时间限制:1.0s   内存限制:256.0MB      问题描述 大家都知道"超级玛丽"是一个很善于跳跃的探险家,他的拿手好戏是跳跃,但它一次只能向前跳 ...

  6. GRE封装解封装过程

    GRE(Generic Routing Encapsulation,通用路由封装)协议是对某些网络层协议(IPX, AppleTalk, IP,etc.)的数据报文进行封装,使这些被封装的数据报文能够 ...

  7. (原)ffmpeg过滤器开发和理解

    最近学习了ffmpeg关于filter过滤器的开发,关于中间的几个相关概念,我们先放在简单介绍一下: AVFilterGraph:几乎完全等同与directShow中的fitlerGraph,代表一串 ...

  8. html button 点击 显示倒计时秒数

    如下: <html> <body> <input type="button" value="click" id="cli ...

  9. 基于【CentOS-7+ Ambari 2.7.0 + HDP 3.0】搭建HAWQ数据仓库——安装配置OPEN-SSH,设置主机节点之间免密互访

    配置root用户免密互访(为了方便,各台系统中使用统一的证书文件)一.安装Open-SSH 1,查询系统中是否安装了openssh [root@]# opm -qa |grep ssh 如已安装,则列 ...

  10. CentOS 6.8 防火墙配置

    系统: CentOS release 6.8 (Final) iptables v1.4.7 执行命令: #清除所有规则 iptables -F #开放redis端口 iptables -A INPU ...