Flask 官方文档解析

2018-06-13  本文已影响0人  Sisyphus235

Flask是用python开发的基于Werkzeug和Jinja2的微Web开发框架。

Mako是一个比Jinja2更强大的template

1.Introduction

作为一个微框架,Flask名副其实,5行可以实现Hello World。(基础介绍请参见Flask基本框架文章)

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, world!"

运行方式

$ pip install Flask
$ Flask_APP=hello.py flask run
 * Running on http://localhost:5000/

2.Installation

Werkzeug是WSGI(Web Server Gateway Interface,简单来说用来连接web server和web application)的工具,Jinja2是提供template的工具。

官方推荐virtualenv方式isntall flask。

virtualenv的好处是隔离不同项目间的环境,避免环境冲突。背后的原因是python的package有很多dependency,彼此之间互相影响,而Python本身版本间也有conflicts。
另外,python跨平台特点有时是因为不同平台package异常的问题而失效的,管理好package dependency是pyton的必修课。

Flask支持python2的2.6+,和python3的3.2+。python3修改了unicode和处理byte的方法,影响HTTP data的处理方法,进而影响WSGI的environ data。

使用virtualenv创建虚拟环境的时候,请尽可能注明python版本。

$ virtualenv venv --python=python3.6

启动virtualenv

$ source venv/bin/activate

停止virtualenv

$ deactivate

3.Quickstart

3.1 基本程序解析

from flask import Flask
app = Flask(__name__)

引入Flask class,创建该class的一个instance,参数是应用的module或者package,为Flask指定去哪里找templates, static files等。

@app.route('/')
def hello_world():
    return 'Hello, world!'

route装饰器指定哪个URL会触发被修饰的函数。这样的设定可以容易的辨别不同函数对于的响应路由,且可以设置动态路由,如下:

@app.route('/user/<username>')
def show_user(username):
    return 'User %s' % username

按照RESTful规范,各级路径名应该是名词性的,动词性的可以用模块来实现动词的功能。

启动文件可以任意命名,比如hello.py,但一般不满意使用flask.py,这样会和Flask起冲突。

flask默认的运行host是127.0.0.1,只能本地debug访问,如果想要他人访问,可以指定host=0.0.0.0

3.2 url_for

url_for()可以产生url,例如:

from flask import Flask, url_for
app = Flask(__name__)
@app.route('/login')
def login(): pass

with app.test_request_context():
     print(url_for('login', next = '/'))
     
输出
/login?next=%2F

3.3 HTTP Methods

默认HTTP methods是GET,可以通过methods参数设定,如下:

from flask import request

@app.route('/login', methods=['GET', 'POST']
def login():
    if request.method == 'POST':
        do_the_login()
    else:
        show_the_login_form()

GET: 浏览器要被请求网页的数据;
HEAD: 浏览器要被请求网页的数据,但只关注headers,而不是page content;
POST: 浏览器传递一些新数据,server要储存且只能储存一次数据;
PUT: 和POST很像,区别是PUT时server可以多次储存数据;
DELETE: 删除相应位置的数据;
OPTIONS: 快速告知client一个URL支持什么样的方法。

3.4 Static Files

储存静态资源,用‘static’作为endpoint name产生URL,如:

url_for('static', filename='style.css')

这个文档要被储存在static/style.css

3.5 Rendering Templates

使用python产生HTML非常笨重,因为要保证安全。Flask默认用Jinja2提供template。例如:

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    reutrn render_template('hello.html', name=name)

使用render_template时,Flask会在templates路径下搜索文件。
在template中,Flask依然支持访问request, session, g, get_flashed_messages()。

3.6 Accessing Request Data

获取client的数据是重要环节,Flask有若干全局变量用来存储这样的数据,request是常用的一个。例如:

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    return render_template('login.html', error=error)

request还能获取上传的文件,例如:

from flask import request
from werkzeug.utils import secure_filename

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename))

secure_filename允许了解client端的文件名。
操作cookies:

# Reading cookies
from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not get a
    # KeyError if the cookie is missing.
    
# Storing cookies
from flask import make_response

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp

3.7 Redirects and Errors

常用两个函数来实现redirets,redirect()和abort()。

from flask import abort, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login')
def login():
    abort(401)
    this_is_never_executed()

用户登录'/'时被redirect到'/login'再被redirect到错误401页面,无法访问任何资源。
Flask默认给每个error code一个页面,如果要定制,可以用errorhandler()装饰器,如:

from flask import render_template

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

3.8 Responses

  1. 如果返回是返回对象类型正确,直接返回;
  2. 如果返回是一个string,response object会被创建,包含返回的string和默认参数;
  3. 如果返回一个tuple,可以提供额外信息,比如(response, status, headers)

如果要定制response,使用make_response()方法,例如:

@app.errorhandler(404)
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp

3.9 Sessions

Session是request之外另一个储存用户数据的全局变量,Session通常存储不同request之间的information。Session在cookie之上,且被加密,client只能读取cookie,不能修改。使用Session需要设置secret key。

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)

@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''

@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))

# set the secret key.  keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

上面的代码没有用template,所以使用了escape()。

secret key最好是随机的,可以使用下面方法来处理
import os
os.urandom(24)

3.10 Message Flashing

用户反馈是网站开发非常重要的部分,message flashing是Flask一种非常方便的用户反馈方式。
可以使用flash()和get_flashed_messages()来处理即时消息。

3.11 Logging

log是网站管理的重要组成部分,flask提供下面的方式记录log。

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')

3.12 Extensions

Flask相当轻便,很多功能可以通过第三方extensions的方式实现,比如Flask-SQLAlchemy提供SQLAlchemy支持。

在使用第三方插件的时候,要尽可能解耦,例如用下面的方式配置。

例如,用第三方sqlalchemy引入db,先创建一个extensions.py来管理第三方引入

# 在extensions里:
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
db.slave_session = db.session

再处理app的初始化,比如在core.py进行初始化

# 在core里
from extensions import db

def create_app():
    app = Flask(__name__)
    app.config.from_object(config)
    config.Config.init_app(app)
    db.app = app
    db.init_app(app)

在model模块从extensions里引入db,这样可以解耦app init和第三方extension

from extensions import db

class BaseModel(db.Model):
    ...

4. Tutorial

http://flask.pocoo.org/docs/0.12/tutorial/#tutorial

5. User Guide

http://flask.pocoo.org/docs/0.12/

上一篇下一篇

猜你喜欢

热点阅读