Flask学习[基础]

Flask是一个基于Werkzeug、Jinja 2和good intentions的Python微框架。
它是开源的,使用BSD开源条款。

开始初步学习

一个最简单的应用

from flask import Flask
app = Flask(__name__)

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

这段代码干了啥?

  1. 首先,我们导入了flask类。我们的wsgi应用里面会有一个这样的实例。
  2. 然后我们创建一个这个类的实例。它的第一个参数就是应用的模块或者包名。如果你只使用了一个模块(就像这个例子中),你应该使用__name__因为取决于它是作为应用程序启动的,还是作为模块导入的,名称将有所不同(__name__对比于真实的导入名)。这是需要的所以Flask直到怎么去查找模板,静态文件等等。对于更多的信息,我们可以在Flask文档中看。
  3. 我们之后会使用route()这个解码器去告诉Flask什么样的URL会触发我们的函数。
  4. 函数给出了个名字用来产生一些URL对于特定的函数,然后返回信息给用户的浏览器。

运行

在linux环境下:

$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/

在windows环境下:
命令行,

C:\path\to\app>set FLASK_APP=hello.py

powershell,

PS C:\path\to\app> $env:FLASK_APP = "hello.py"

或者,你可以用这个python -m flask

$ export FLASK_APP=hello.py
$ python -m flask run
 * Running on http://127.0.0.1:5000/

这启动一个非常简单的内联服务器,足够用来测试,但可能不是你实际生产中使用的。对于部署选项,见 Deployment Options。
现在跳转到http://127.0.0.1:5000/。

外部可见的服务器

如果你运行你的服务器,你会发现你的服务器只能用于你的计算机中,不来来自于其他的网络。这是默认的,因为在调试模型一个用户的应用可以执行你计算机中任意的代码。

如果你关闭你的调试器,然后信任你用户的网络。你可以让你的服务器公开使用通过添加–host =0.0.0.0 到命令行。

这告诉您的操作系统监听所有公共ip。

如果你的服务器没有运行

如果python -m flask失败或烧瓶不存在,可能有多种原因。首先,您需要查看错误消息。

旧版本的flask

大于0.11的flask版本用于以不同的方式启动应用程序。简而言之,flask命令不存在,python -m flask也不存在。在这种情况下,您有两种选择:升级到新的烧瓶版本,或者查看开发服务器文档,查看运行服务器的替代方法。

无效的导入名

FLASK_APP环境变量是要在flask运行时导入的模块的名称。如果模块名称不正确,您将在启动时得到一个导入错误(或者在导航到应用程序时启用了debug)。它将告诉您它试图导入什么以及为什么失败。

最常见的原因是输入错误,或者因为您实际上没有创建app对象。

调试模式

(只想记录错误和堆栈跟踪吗?查看应用错误)

flask脚本很适合来启动一个本地开发服务器,但是你会手动重启它在你的代码都改变后。那不是很好,而且flask能够做得更好。如果你启动调试支持,服务器会重载它自己的代码改变,它也会给你提供一个有帮助的调试器如果哪里错了。

要启用所有开发特性(包括调试模式),可以导出FLASK_ENV环境变量,并在运行服务器之前将其设置为development:

$ export FLASK_ENV=development
$ flask run

在windows中你需要使用set而不是export。

这做了以下的事情:

  1. 它激活了调试器。
  2. 它激活了自动装载器。
  3. 它启动了flask程序的调试模式。

您还可以通过导出FLASK_DEBUG=1来独立于环境控制调试模式。

开发服务器文档中解释了更多的参数。

**注意:**即使交互式调试器不能在分叉环境中工作(这使得它几乎不可能在生产服务器上使用),它仍然允许执行任意代码。这使得它成为一个主要的安全风险,因此它绝不能在生产机器上使用。

路由

现代web应用程序使用有意义的url来帮助用户。用户更有可能喜欢某个页面,如果该页面使用了一个他们能够记住并用于直接访问某个页面的有意义的URL,他们就会再次访问该页面。
使用装饰器route()去绑定一个函数到一个URL:

@app.route('/')
def index():
    return 'Index Page'

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

变量规则

您可以通过使用<variable_name>构造sections来向URL添加变量sections。然后函数接收<variable_name>作为关键字参数。您还可以选择使用转换器来指定参数的类型,比如converter:variable_name

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % subpath

转换器类型:

  • string: (默认) 接受任何没有斜杆的文本
  • int: 接受任何正数
  • float: 接受正浮点数的值
  • path: 就像字符串一样但接受斜线
  • uuid: 接受一个UUID 字符串

独特URLs/重定向行为

下面两条规则在使用尾随斜杠时有所不同。

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'

项目端点的规范URL后面有一个斜杠。它类似于文件系统中的文件夹。如果访问URL时不使用尾随斜杠,flask将用尾随斜杠将您重定向到规范URL。

about端点的规范URL后面没有斜杠。它类似于文件的路径名。使用尾随斜杠访问URL会产生404“Not Found”错误。这有助于保持这些资源的url唯一性,这有助于搜索引擎避免对同一个页面进行两次索引。

URL 构建

创建一个URL到一个特定的函数,使用 url_for() 函数。它接受了函数的名作为它的第一个参数,或者任何数量的关键词参数,每个对应于URL规则的可变部分。未知的变量部分加入到URL作为查询参数。

为什么你想要构造一个URLs使用URL完全Reversing的函数url_for()而不是将它们硬编码到模板中?

  1. Reversing通常比硬编码url更具描述性。
  2. 您可以一次性更改url,而不需要记住手动更改硬编码的url。
  3. URL构建透明地处理特殊字符和Unicode数据的转义。
  4. 生成的路径总是绝对的,避免了浏览器中相对路径的意外行为。
  5. 如果您的应用程序位于URL根目录之外,例如,在
    /myapplication而不是/,url_for()为您正确地处理了这个问题。

例如,这里我们使用test_request_context()方法来尝试url_for().test_request_context()告诉flask,即使在使用Python shell时,它的行为也要像在处理请求一样。当地人看到上下文。

from flask import Flask, url_for

app = Flask(__name__)

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

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

@app.route('/user/<username>')
def profile(username):
    return '{}\'s profile'.format(username)

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

/
/login
/login?next=/
/user/John%20Doe

HTTP 方法

web应用使用不同的HTTP方法当获取URL资源时。你应该熟悉自己当你使用HTTP方法跟Flask。默认的,一个route只响应获取请求。你能够使用route()装饰器方法参数去操纵不同的HTTP方法。

from flask import request

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

如果有GET,Flask会自动添加对HEAD方法的支持,并根据HTTP RFC处理HEAD请求。同样,选项也会自动为您实现。

静态文件

动态web应用也需要静态文件。这通常是CSS和JavaScript文件的来源。理想上,你的web服务器被配置去服务它们给你,但在开发过程中Flask也能做到这一点。只要在包中或模块旁边创建一个名为static的文件夹,就可以在应用程序的/static中使用它。

要为静态文件生成url,请使用特殊的“静态”端点名称:
url_for(‘static’, filename=‘style.css’)
文件必须以静态/style.css的形式存储在文件系统中。

渲染模板

从Python中生成HTML并不有趣,而且实际上相当麻烦,因为您必须自己执行HTML转义以保持应用程序的安全性。因为有了这个flask使用了Jinja2模板引擎就会自动为您配置。

要呈现模板,可以使用render_template()方法。您所要做的就是提供模板的名称以及作为关键字参数传递给模板引擎的变量。下面是一个如何渲染模板的简单例子:

from flask import render_template

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

Flask将在templates文件夹中查找模板。如果你的应用是一个模块,这个文件夹就在那个模块旁边,如果它是一个包,它就在你的包里面:
案例1: 一个模块:

/application.py
/templates
    /hello.html

案例 2: 一个包

/application.py
/templates
    /hello.html

对于模板,您可以使用Jinja2模板的全部功能。要了解更多信息,请访问官方的Jinja2模板文档。
这里是一个模板的例子:

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

在模板内部,您还可以访问请求、会话和对象以及**get_flashed_messages()**函数。

如果使用继承,模板尤其有用。如果您想知道它是如何工作的,请访问模板继承模式文档。基本上,模板继承使在每个页面上保留某些元素成为可能(如页眉、导航和页脚)。

启用自动转义,因此如果名称包含HTML,它将自动转义。如果您可以信任一个变量,并且知道它是安全的HTML(例如,因为它来自一个将wiki标记转换为HTML的模块),那么您可以使用标记类或模板中的|安全过滤器将它标记为安全的。有关更多示例,请参阅Jinja 2文档。

下面是对Markup类工作原理的基本介绍:

>>> 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'

获取Request数据

对于web应用程序,对客户机发送给服务器的数据做出响应是至关重要的。在Flask中,这个信息是通过全局request对象来提供的。如果你有一些python的经验你可能会好奇那个对象是如何能变全局以及Flask如何设法保持线程安全。回答是本地上下文:

本地上下文:

内幕信息:
如果您想了解它是如何工作的,以及如何使用上下文局部变量实现测试,请阅读本节,否则就跳过它。
Flask中一定的对象是全局对象,但并不是通常的类型。这些对象实际上是特定上下文的本地对象的代理。一口,但这其实很容易理解。

假设上下文是处理线程。一个请求出现,web服务器决定生成一个新线程(或者其他东西,底层对象能够处理线程之外的并发系统)。当Flask启动其内部请求处理时,它指出当前线程是活动上下文,并将当前应用程序和WSGI环境绑定到该上下文(线程)。它以一种智能的方式实现这一点,这样一个应用程序可以调用另一个应用程序而不会中断。

这对你来说意味着什么?基本上你可以完全忽略这一点,除非你在做单元测试之类的事情。您将注意到,依赖于请求对象的代码将突然中断,因为没有request对象。解决方案是自己创建一个request对象并将其绑定到上下文。单元测试最简单的解决方案是使用test_request_context()上下文管理器。与with语句结合使用,它将绑定一个测试请求,以便您可以与之交互。举个例子:
传递参数。

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对象被记录在API部分中,我们将不在这里详细讨论它(参见请求)。下面是一些最常见操作的概述。首先你必须从Flask模块导入:

from flask import request

通过使用method属性可以使用当前请求方法。要访问表单数据(在POST或PUT请求中传输的数据),可以使用form属性。以下是上述两个属性的完整示例:

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

如果key没有存在于form属性中,会发生什么?在那种情况下,一个特殊的KeyError抛出,你能够抓住它就像一个标准的KeyError,但如果你捕获它,那么一个HTTP400 Bad Request错误会在里面发生。所以,对于很多种情况下,你必须去处理那样的问题。

要访问URL (?key=value)中提交的参数,可以使用args属性:

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

我们建议使用get或捕捉KeyError访问URL参数,因为在这种情况下,用户可能更改URL并显示400错误请求页面,这对用户不友好。

有关请求对象的方法和属性的完整列表,请转到请求文档。

文件上传

你可以用Flask很简单的操纵文件上传。只要确保不要忘记在HTML表单上设置enctype="multipart/form-data"属性,否则浏览器根本不会传输您的文件。

上传的文件存储在内存中或文件系统上的临时位置。您可以通过查看请求对象上的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属性。然而你一定要记得这个值可以被伪造,不要信它。如果您想使用客户机的文件名将文件存储在服务器上,请通过Werkzeug为您提供的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))

猜你喜欢

转载自blog.csdn.net/xiabenshu/article/details/88955634