美文网首页
Flask 官方文档解析

Flask 官方文档解析

作者: Sisyphus235 | 来源:发表于2018-06-13 15:10 被阅读0次

    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/

    相关文章

      网友评论

          本文标题:Flask 官方文档解析

          本文链接:https://www.haomeiwen.com/subject/eavjeftx.html