flask-quickstart 官方网站翻译

翻译的网站
备注 我只会翻译一些关键点。太简单的就不翻译了

Quickstart

一个小程序可能看起来会是这样的

#hello.py
from flask import Flask
app = Flask(__name__)

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

通过命令行启动程序有两种方式

# 1.
export FLASK_APP=hello.py
flask run
#2.
export FLASK_APP=hello.py
python -m flask run

如果想让你的程序成为可访问的公共服务器

flask run --host=0.0.0.0

如果启动成功你就可以通过 http://127.0.0.1:5000来看到你的Hello, World!

失败的原因可能有多种,有可能是你的flask版本过低,也有可能导入的包名无效,或者你也可以开启Debug模式

export FLASK_DEBUG=1

在这种模式下,flask能够提供有用的调试信息,也能够自动监听代码改动而重启服务器。
另外,不建议你在开发阶段,通过在代码中使用如下方法启动服务器。

if __name__ == '__main__':
    app.run()

flask 匹配与生成url的两个函数

@app.route('/user/<username>')
... def profile(username): pass
url_for('profile',username='john deo')

Http(超文本协议) 传输方法

from flask import request

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

http PUT

PUT与POST类似,但服务器能通过覆盖旧值多次激发存储程序,例如传输过程种程序与服务器断开连接,PUT能够在不中断服务的情况下安全的接受二次请求,而POST做不到。

静态资源

包括css js 图片等,flask都会默认在static文件中寻找它们。所以你要使用静态文件,首先要建立static文件夹。

获得静态文件的地址可以通过

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

Html模版

默认的flask从template文件夹中寻找模版,确保它在你的模块或包中
flask 封装了jinja2模版引擎,模版中你仍然可以使用 request, session and g [1] 这些对象以及像 get_flashed_messages() 函数.
如果你想了解更多模版继承的东西,可以查看 Template Inheritance ,它使得可以把像header, navigation and footer的东西放在一个页面中。

flask可以自动忽略过滤变量中的html标记,所以如果你信任它,可以通过 Markup或者|safe 过滤器标签来标记它是安全的不用过滤

>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML'

现在自动过滤并不对全部模版适用了,自动过滤只对后缀为.html, .htm, .xml, .xhtml. 的文件适用。

请求数据

flask提供了全局对象request来解决客户端到服务器的数据处理反应。你可能会对flask如何将它变为全局可用且维持它的线程安全。答案就是上下文变量。

flask 能够确保你在多线程环境中,获得活动线程正确的数据

Context Locals 上下文变量

如果你想理解它是如何工作的,并且测试一下,那么可以读一下接下来的部分。

flask中的全局对象和我们通常意义上的不同,它们只是某些特定上下文环境中的菊部变量的代理。

想象一个上下文环境,它是一个正在处理请求的线程。这时又来了一个请求,web服务器决定开辟一个新的线程(或者采用协程的方式),当flask开始进行内部处理这个请求的时候,flask计算出当前线程是活动的上下文环境,并且把当前的应用程序与wsgi环境同这个线程绑定起来。它通过一种智能的方式完成程序在不中断情况下的协同工作。

wow 这对你意味着什么,意味着你可以不用操心当前处于什么上下文环境而放心的使用全局变量。当然如果你要做一些单元测试,那就行不通了。这时猴你发现代码中以来的request对象没有了,解决方法就是你自己创建一个并和上下文绑定。最简单的方法是使用test_request_context() context manager这个上下文管理器,通过使用with语句绑定一个test request,然后你就可以使用它了。

from flask import request

with app.test_request_context('/hello', method='POST'):
    # now you can do something with the request until the
    # end of the with block, such as basic assertions:
    assert request.path == '/hello'
    assert request.method == 'POST'

或者你也可以传递整个WSGI环境给 request_context()方法

from flask import request

with app.request_context(environ):
    assert request.method == 'POST'

Request 对象

表单数据

关于 request的详细解释,可以在这找到。我们接下来只进行常用方法的概述。
首先你要从flask模块中导入它

from flask import request

最常用的请求方法是通过method属性

@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'
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template('login.html', error=error)

通过request.form来获取表单数据,如果没有这个属性,则抛出 KeyError,你可以自己捕获它,或者让他自动使用HTTP 400 错误页面。

获取URL中的查询字符串,可以采用

searchword = request.args.get('key', '')

文件上传

只要你在你的表单头中设置了

enctype="multipart/form-data"

flask可以轻松处理你上传的文件。上传的文件被存储在内存或临时文件系统中,你能够通过request的files属性获取它。所有上传的文件都被存在这个属性字典中,它就像标准的python文件,并且能够让你通过save方法来保存它。下面是个简单示例。

from flask import request

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

通过filename属性,你能够获得客户端上传文件的文件名,但它能够被轻易伪造,所以更安全但方法是通过 secure_filename()方法。

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))
    ...

更多例子,点击 Uploading Files.

Cookies

你可以通过cookies属性来获取cookies,通过response对象的set_cookie 方法来设置cookie

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.
from flask import make_response

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

注意到cookies是设置在response对象上的,当你从视图函数中返回字符串,Flask会转化成reponse对象,你也可以通过 make_response()函数明确的来返回它,并且修饰它。
('有时候需要在返回的时候设置headers,这时候你就需要make_respone函数来明确返回一个response object')
有时候你想要在response对象还不存在的时候创建cookie,你就需要利用 Deferred Request Callbacks 模式。
Deferred Request Callbacks最重要的关键点是before_request与after_request函数,这两个函数分别是注册一个函数在request之前和之后执行。before_request被注册的函数没有参数,after_request注册的函数有一个参数 response_class的实例,并且返回一个response 对象。

from flask import g
#自定义装饰器,通过g来传递数据
def after_this_request(f):
    if not hasattr(g, 'after_request_callbacks'):
        g.after_request_callbacks = []
    g.after_request_callbacks.append(f)
    return f

from flask import request
#在处理request前执行,如果没有错误,进入视图函数执行
@app.before_request
def detect_user_language():
    language = request.cookies.get('user_lang')
    if language is None:
        language = guess_language_from_request()
        @after_this_request #自定义装饰器,将下面的函数放入g对象属性中,此时response不存在
        def remember_language(response):
            response.set_cookie('user_lang', language)
    g.language = language

#request在视图函数处理返回response后执行
@app.after_request
def call_after_request_callbacks(response):
    for callback in getattr(g, 'after_request_callbacks', ()):
        callback(response)
    return response

Redirects and Errors 重定向与错误

记住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()

默认的flask提供一套简单的error page,如果想自定义,使用 errorhandler() 装饰器:

from flask import render_template

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

调用 render_template() 后的404告诉 Flask页面没找到,默认是200,表示一切都好。

关于Responses

flask将返回值转化为response对象的逻辑规则如下:
1、如果返回正确类型的response对象,视图函数直接返回。
2、如果返回的是字符串,flask将string与一些默认参数转化为response对象。
3、如果是一个元组,那么必须以(response, status, headers) 或 (response, headers)的形式出现,至少有一项必须存在。status value 将会覆盖status,headers可以以列表或字典的形式出现。

如果你想在视图中控制返回对象,使用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

Sessions

除request对象外还有一个session对象。session对象能够让你在request之间保存一些对用户来说具体的信息。它是基于cookie的,并为其加密。也就是说它只能够读,但不能够修改,除非你知道了密码。

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

app = Flask(__name__)

@app.route('/')
def index():
    if 'username' in session:
     #Convert the characters &, <, >, ‘, and ” in string s to HTML-safe sequences
        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'

How to generate good secret keys?
如何产生好用的秘钥

import os
os.urandom(24)

flask 默认的是客户端session,如果你想处理服务端的,可以使用flask扩展解决。

Message Flashing

flask提供应用程序与用户之间良好交互的方法。它在一个请求结束后记录message,在下一个(仅下一个)请求中获得它。
flash 例子 更多细节 Message Flashing

from flask import Flask, flash, redirect, render_template, \
     request, url_for

app = Flask(__name__)
app.secret_key = 'some_secret'

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

@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != 'admin' or \
                request.form['password'] != 'secret':
            error = 'Invalid credentials'
        else:
            flash('You were successfully logged in') #这里调用flash函数
            return redirect(url_for('index'))
    return render_template('login.html', error=error)

<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages() %} #前端调用该函数
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
{% block body %}{% endblock %}

Logging

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

logger 是一个标准的logging Logger,可查看官方的 logging documentation获得更多信息。

WSGI 中间件

不了解wsgi的可看一下我的另一篇文章带你快速了解WSGI

(middleware需要把自己伪装成一个服务器,接受应用程序,调用它,同时middleware还需要把自己伪装成一个应用程序,传给服务器程序。)
如果你想在你的程序中增加一个wsgi中间件,你可以包装内部的wsgi应用程序。你可以像下面这样做来使用LighttpdCGIRootFix中间件。

from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)

Flask 扩展

扩展都在这里

网站发布

看这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容