一篇文章入门Flask

栏目: Python · 发布时间: 5年前

内容简介:Flask本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login),都需要用第三方的扩展来实现。Flask对WSGI (路由)的实现,是采用 Werkzeug,而模板引擎(业务视图) 则使用 Jinja2。这两个是Flask框架的核心。Flask核心就是作为一个Webapp框架的两个基础部分:

Flask本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login),都需要用第三方的扩展来实现。

Flask对WSGI (路由)的实现,是采用 Werkzeug,而模板引擎(业务视图) 则使用 Jinja2。这两个是Flask框架的核心。

Flask核心就是作为一个Webapp框架的两个基础部分:

  • CGI (WSGI) 路由:是由Werkzeug实现,即将网络请求翻译成 Python 语言
  • Template 业务模版:是由Python流行的Jinja2实现

除此之外,Flask其它一切的都是由第三方插件实现:

包括:

Flask-SQLalchemy:操作数据库; Flask-migrate:管理迁移数据库; Flask-Mail:邮件; Flask-WTF:表单; Flask-Bable:提供国际化和本地化支持,翻译; Flask-script:插入脚本; Flask-Login:认证用户状态; Flask-OpenID:认证; Flask-RESTful:开发REST API的工具; Flask-Bootstrap:集成前端Twitter Bootstrap框架; Flask-Moment:本地化日期和时间; Flask-Admin:简单而可扩展的管理接口的框架

参考Flask扩展列表: http://flask.pocoo.org/extens...

Flask安装

安装很简单:

$ pip install flask

建议在Virtualenv虚拟环境下安装,因为Flask需要一系列的依赖,最好给Flask生成一个专用的生产环境,并生产 requirement.txt 依赖列表:

# 生产虚拟环境
$ virtualenv ./flask_env
# 启动虚拟环境
$ ./flask_env/bin/active
# 生产依赖列表
$ pip freeze > requirements.txt

Hello World

一个最简单的Flask程序,只需要三步:

路由规则
app.run()

hello-world.py

from flask import Flask

# 生产一个Flask APP 实例,并指向当前文件(模块)
app = Flask(__name__)

# 指定"/"根目录的路由规则
@app.route('/')
def index():
    return 'Hello World'

# 开始运行app
app.run()

Flask中,路由的实现是用装饰器: @app.route("/") 这种方式来做到的。

Flask路由规则

页面显示指定内容:

@app.route('/')
def index():
    return '<h1> 欢迎访问此页面 </h1>'

页面返回指定内容、状态码、headers等:

@app.route('/')
def index():
    body = '<h1> 欢迎访问此页面 </h1>'
    status_code = 200
    headers = {'Cache-Control':'no-cache', 'Connection':'keep-alive'}
    return body, status_code, headers

指定接收的 请求方式

@app.route('/', method='GET')
# ...

给路由传参数:

@app.route('/orders/<order_id>')
def hello_itheima(order_id):
    return 'The ID of order is: %d' % order_id

限制路由参数的数据类型:

@app.route('/orders/<int:order_id>')
# ...

其中 int:order_id 是指定参数 order_id 必须能转换成int整数,否则这个请求就会自动被拒绝。

比如用户请求 http://xyz.com/orders/HAHAHAH ,这就不成功。而 http://xyz.com/orders/210 这样的就成功。

一篇文章入门Flask

中断请求:

# ...

from flask import abort

@app.route('/wrong-page')
def hello():
    # 中断请求,并返回404状态码
    abort(404)

处理错误请求:

# ...

@app.errorhandler(404)
def handel_404_error():
    return '<h1> The page does not exist </h1>'

其中,如果路由中调用了 abort(404) 中断函数,或是其它产生404错误的方法,这个 app.errorhandler 都会被自动调用。

返回“渲染”过的模版(即把动态的模版渲染成静态的HTML):

#...
from flask import render_template

@app.route('/')
def index():
    return render_template('index.html')

Flask 路由分割

如果所有路径的路由都定义在一个文件里,会很难维护,所以必定要把各个路径的路由分拆到不同的文件里。

这种分拆很简单:

正常情况下,在 index.py 主模块中,我们还是一样正常的定义路由:

#...
@app.route('/')
def index():
   pass

然后我们可以把其它路由的处理函数分别放在别的文件里,比如:

register.py 中定义“普通函数”:

def reg():
    pass

以及 login.py 中定义一个普通函数:

def signin():
    pass

然后回到主模块 index.py 中,我们可以导入这些函数,并显式的将这些函数注册到路由上:

from flask import Flask

from register import reg
from login import signin

app = Flask(__name__)

app.route('/register')(reg)
app.route('/login')(signin)

@app.route('/')
def index():
    pass

然后我们可以用 app.url_map 获得当前定义过的所有路由:

print( app.url_map )

一篇文章入门Flask

Flask Blueprint 蓝图

我们手动分割路由处理函数,然后分别导入,这样虽然也简单,但是不不好的地方是,主模块外定义的各个处理函数,本身很难看出来处理的是什么路由逻辑。

为此,Flask提供了另一种 路由分割 的方法:即 Blueprint 类。

而这个Blueprint类生成的对象,是在子模块中代替了之前我们所使用的 Flask 类生成的app对象。

也就是说:主模块还是用app,但是子模块中用蓝图blueprint。

假设我们现在有一个子模块 order.py 定义 "/order" 路径的路由,那么文件中定义如下:

from flask import Blueprint

# 生成蓝图实例:参数中一个是蓝图名称,一个是主模块名称
app_orders = Bluepint('blueprint_orders', __name__)

# 将路由添加到蓝图里
@app_orders.route('/orders')
def get_orders():
    pass

然后回到主模块 index.py 中,把蓝图注册到主路由上:

#...
from orders import app_orders

app = Flask(__name__)

app.register_blueprint( app_orders )

#...

Hooks 钩子事件

Flask提供一个完整请求至回应的事件流,其中包括:

@app.before_first_request
@app.before_request
@app.route()
@app.after_request

- @app.teardown_request : 关闭请求时,即每次请求是否异常都会被执行

以下是钩子的用法:

#...

@app.before_first_request
def handle_before_first_request():
    pass

@app.route('/')
def index():
    pass

@app....
def ...

Flask上下文请求对象 flask.current_app

request.current_app 是Flask特有的一种 request请求处理 方式,不同于 flask.request 对象的处理方式,它是能区分多个请求的。

在我们常用的 flask.request 对象中,会有一个很严重的问题:即它是一个 全局变量 。也就是说,如果服务器在处理并发请求时使用的是在同一个进程里的多线程,那么不同用户的请求也许会使用同一个 flask.request 对象!这时候request中的请求信息就会出现混淆!

所以Flask引入了 request.current_app 这个对象,即它能够根据上下文来区分不同人的请求。

这是怎么做到的呢?其实很简单,它只是把request变为一个 局部变量 而已。这样一来,每次的request请求,都是各自独立的局部对象。

返回响应信息 flask.make_response

除了我们自己定义返回的信息外,Flask提供了一个内置的 make_response 对象,便于处理返回信息。

返回全文信息:

from flask import make_response

@app.route('/')
def index():
    resp = make_response('<h1> 欢迎访问此页面 </h1>')
    resp.status = 200
    resp.headers['Cache-Control'] = 'no-cache'
    return resp

设置cookies:

from flask import make_response

@app.route('/')
def index():
    resp = make_response('<h1> 此页面会设置你的cookies :) </h1>')
    resp.set_cookie('uuid', '1230sfjdlsj3uu')
    resp.set_cookie('name', 'Jason', max_age=360)
    return resp

其中, max_age 是cookie的存活时间,以s秒为单位。不设置的话,默认是 临时cookies ,即浏览器关闭后立马失效。

删除cookie: resp.delete_cookie('uuid') 。注意,这里的删除并不是立马删除浏览器中用户的cookie,而只是把 max_age 设置为0,即浏览器关闭后立马失效。

获取请求信息 flask.request

Flask中有一个request对象,接收了一切对当前模块的请求数据。

使用的话,直接在 @app.route 后面的函数中用 def index(request) 接收来自装饰器的请求对象即可使用。

request参数类型:

一篇文章入门Flask

常用的各种类型操作如下:

from flask import request 
app = Flask(__name__)

@app.route('/', method='POST')
def index(request):
    # Get uploaded file
    afile = request.files.get('pic')
    with open('./pic.jpg', 'w') as f:
        f.write( afile.read() )

    # Get a form
    form = request.from    # Dict类型
    name = form.get('name')
    age = form.get('age')

    # Get cookies
    uuid = request.cookies.get('uuid')
    name = request.cookies.get('name')

会话处理 flask.session

在登录页设置session,并在index页根据session判断是否登录:

from flask import session
#...

app.config['SECRET_KEY'] = 'asdlkjflaj23jrsdjf任意字符串作为密钥kaljdsl;fkja;j'

@app.route('/login')
def login():
    # 设置sessions
    session['uuid'] = '123abadsf'
    return '<p> 登录成功 </p>'

@app.route('/')
def index():
    # 获取sessions
    uuid = session['uuid']
    # 判别session是否存在
    if uuid:
        return '<p> 之前已登录过 </p>'
    else:
        return '<p> 未登录,请重新登录 </p>'

其中,Flask默认情况下,会利用 app.config['SECRET_KEY'] 的值作为一个密钥,来加密你手动设置的session,然后把这个信息转换为名叫 session 的cookie存在浏览器中。

这个是Flask特别的一点。

但是把敏感的session数据保存到谁都能访问的cookie中,即使加密了也不是很安全。

所以一般我们还是会手动把session数据存到服务器后台的数据库中,而不是存到cookie中。

每次验证再与数据库进行对比。

表单处理 request.form

动态网页必须要的就是Form表单。Flask中有自带的form表单处理方法。不过我们也可以用第三方插件 Flask-WTF 实现。

这里我们先只讲自带的处理方式。

Flask自带表单处理

假设我们有一个表单模版 form.html

<form method="post">

    用户名:<input type="text" name="username">
    密码: <input type="password" name="password">
    确认密码: <input type="password" name="password2">

    <input type="submit" value="提交"><br>

    {% for message in get_flashed_messages() %}
        {{ message }}
    {% endfor %}
    
</form>

当用户点击submit提交时,

整个form信息就会用POST方式提交到Flask的路由文件 abc.py 中。

我们进行处理如下:

from flask import Flask
from flask import render_template
from flask import request

app.secret_key = 'abc123'

@app.route('/', methods=['GET', 'POST'])
def hello():

    if request.method == 'POST':

        # 获取参数, 并效验参数完整性, 如果有问题就进行flash
        username = request.form.get('username')
        password = request.form.get('password')
        password2 = request.form.get('password2')

        if not all([username, password, password2]):
            flash('params error')
        elif password != password2:
            flash('password error')
        else:
            print username
            return 'success'

    return render_template('Congratulations.html')

Flask的HTTP Server

一般我们在开发调试过程中,可以用Flask自带的WSGI和一个小HTTP Server来实现整个App正常运转。

但是生产环境中,这两个自带的组件就效率很低了。所以我们需要用效率更高的独立的CGI和独立的HTTP Server服务器来部署真正的生产环境

一般常见的选项有:

  • HTTP Server -> 首推Nginx
  • CGI翻译器 -> Gunicorn (Python开发,实现了WSGI翻译)

所以,我们一般采用 Nginx + Gunicorn + Flask 来部署网络应用。

Gunicorn的使用:

# 安装
$ pip install gunicorn

# 进入Flask app的主目录
cd ./myFlask

# 用gunicorn服务器启动Flask app
$ gunicorn -w 4 -b 127.0.0.1:8080 main:app

这个时候,flask就在gunicorn的HTTP服务器上运行了,可以通过127.0.0.1:8080访问到app。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

编译原理

编译原理

Alfred V. Aho、Monica S.Lam、Ravi Sethi、Jeffrey D. Ullman / 赵建华、郑滔、戴新宇 / 机械工业出版社 / 2008年12月 / 89.00元

本书全面、深入地探讨了编译器设计方面的重要主题,包括词法分析、语法分析、语法制导定义和语法制导翻译、运行时刻环境、目标代码生成、代码优化技术、并行性检测以及过程间分析技术,并在相关章节中给出大量的实例。与上一版相比,本书进行了全面的修订,涵盖了编译器开发方面的最新进展。每章中都提供了大量的系统及参考文献。 本书是编译原理课程方面的经典教材,内容丰富,适合作为高等院校计算机及相关专业本科生及研......一起来看看 《编译原理》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具