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. PEP 492 -- Coroutines with async and await syntax 翻译

    因为工作中慢慢开始用python的协程,所以想更好的理解一下实现方式,故翻译此文 原文中把词汇表放到最后,但是我个人觉得放在最开始比较好,这样可以增加当你看原文时的理解程度 词汇表 原生协程函数 Na ...

  2. Linux基础知识之用户和用户组以及 Linux 权限管理

    已经开始接触Linux用户管理,用户组管理,以及权限管理这几个逼格满满的关键字.这几个关键字对于前端程序猿的我来说真的是很高大上有木有,以前尝试学 Linux 的时候看到这些名词总是下意识的跳过不敢看 ...

  3. mysql分区方案的研究

    笔者觉得,分库分表确实好的.但是,动不动搞分库分表,太麻烦了.分库分表虽然是提高数据库性能的常规办法,但是太麻烦了.所以,尝试研究mysql的分区到底如何. 之前写过一篇文章,http://www.c ...

  4. 常用MQ及其原理

    mq为了解决什么问题?1.异步通信   有些业务不想也不需要立即处理消息.消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它.想向队列中放入多少消息就放多少,然后在需要的时候再去 ...

  5. android sdk manager更新地址

    参考:http://www.oschina.net/question/1399261_195245 android sdk 用久了,想更新到最新的SDK包: 大连东软信息学院镜像服务器地址:- htt ...

  6. DirectX using C++_error X3539:ps1_x is no longer supported...解决方案

    问题来源 在研究HLSL时编译一个demo出现了error X3539的问题 解决方案 将代码中的ps_1_1 改为ps_2_0 PixelShader = compile ps_1_1 PS(); ...

  7. koa文档参考

    koa文档 简介 koa 是由 Express 原班人马打造的,致力于成为一个更小.更富有表现力.更健壮的 Web 框架.使用 koa 编写 web 应用,通过组合不同的 generator,可以免除 ...

  8. Java Observer接口和Observable类实现观察者模式

    对于观察者模式,其实Java已经为我们提供了已有的接口和类.对于订阅者(Subscribe,观察者)Java为我们提供了一个接口,JDK源码如下: package java.util; public ...

  9. 转:十步完全理解SQL

    来自:http://blog.jobbole.com/55086/ 很多程序员视 SQL 为洪水猛兽.SQL 是一种为数不多的声明性语言,它的运行方式完全不同于我们所熟知的命令行语言.面向对象的程序语 ...

  10. 121、Data Binding(数据绑定)(转载)

    http://www.jianshu.com/p/b1df61a4df77 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/060 ...