Python Flask框架 快速上手 文档 (3.1.x) -Quickstart 中英文对照

Quickstart

Eager to get started? This page gives a good introduction to Flask. Follow Installation to set up a project and install Flask first.

迫不及待要开始了?本页为 Flask 提供了一个很好的入门介绍。请先按照 Installation 页面设置项目并安装 Flask。

A Minimal Application  一个极简的应用程序 ¶

A minimal Flask application looks something like this:
一个最小的 Flask 应用程序看起来像这样:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

So what did that code do?
这段代码做了什么?

  1. First we imported the Flask class. An instance of this class will be our WSGI application.

    首先我们导入了 Flask 类。这个类的一个实例将会是我们要使用的 WSGI 应用程序。

  2. Next we create an instance of this class. The first argument is the name of the application’s module or package. __name__ is a convenient shortcut for this that is appropriate for most cases. This is needed so that Flask knows where to look for resources such as templates and static files.

    接下来我们创建这个类的一个实例。第一个参数是应用程序模块或包的名称。 __name__ 是一个方便的快捷方式,在大多数情况下适用。这需要让 Flask 知道去哪里查找资源,例如模板和静态文件。

  3. We then use the route() decorator to tell Flask what URL should trigger our function.

    然后我们使用 route() 装饰器来告诉 Flask 哪个 URL 应该触发我们的函数。

  4. The function returns the message we want to display in the user’s browser. The default content type is HTML, so HTML in the string will be rendered by the browser.

    函数返回我们希望在用户浏览器中显示的消息。默认内容类型是 HTML,因此字符串中的 HTML 将由浏览器渲染。

Save it as hello.py or something similar. Make sure to not call your application flask.py because this would conflict with Flask itself.保存为 hello.py 或类似名称。请确保不要将应用程序命名为 flask.py ,因为这将与 Flask 本身发生冲突。

To run the application, use the flask command or python -m flask. You need to tell the Flask where your application is with the --app option.要运行应用程序,请使用 flask 命令或 python -m flask 。您需要通过 --app 选项告诉 Flask 您的应用程序位置。

$ flask --app hello run
 * Serving Flask app 'hello'
 * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)

Application Discovery Behavior
应用程序发现行为

As a shortcut, if the file is named app.py or wsgi.py, you don’t have to use --app. See Command Line Interface for more details.作为快捷方式,如果文件名为 app.pywsgi.py ,则无需使用 --app 。有关详细信息,请参阅命令行界面。

This launches a very simple builtin server, which is good enough for testing but probably not what you want to use in production. For deployment options see Deploying to Production.这将启动一个非常简单的内置服务器,适用于测试,但可能不适合生产环境。有关部署选项,请参阅部署到生产环境。

Now head over to http://127.0.0.1:5000/, and you should see your hello world greeting.现在访问 http://127.0.0.1:5000/ ,你应该会看到你的 hello world 欢迎信息。

If another program is already using port 5000, you’ll see OSError: [Errno 98] or OSError: [WinError 10013] when the server tries to start. See Address already in use for how to handle that.如果另一个程序已经使用了端口 5000,当服务器尝试启动时,你会看到 OSError: [Errno 98]OSError: [WinError 10013] 。有关如何处理这种情况,请参见地址已被使用。

Externally Visible Server
外部可见服务器

If you run the server you will notice that the server is only accessible from your own computer, not from any other in the network. This is the default because in debugging mode a user of the application can execute arbitrary Python code on your computer.
如果你运行服务器,你会发现服务器只能从你自己的电脑访问,而不能从网络上的其他电脑访问。这是默认设置,因为在调试模式下,应用程序的用户可以在你的电脑上执行任意的 Python 代码。

If you have the debugger disabled or trust the users on your network, you can make the server publicly available simply by adding --host=0.0.0.0 to the command line:如果你禁用了调试器或者信任网络上的用户,你可以通过在命令行中添加 --host=0.0.0.0 使服务器对外公开。

$ flask run --host=0.0.0.0

This tells your operating system to listen on all public IPs.
这会告诉你的操作系统在所有公网 IP 上监听。

Debug Mode  调试模式 ¶

The flask run command can do more than just start the development server. By enabling debug mode, the server will automatically reload if code changes, and will show an interactive debugger in the browser if an error occurs during a request.flask run 命令不仅可以启动开发服务器。通过启用调试模式,服务器会在代码更改时自动重新加载,并且在请求过程中发生错误时会在浏览器中显示交互式调试器。

Warning  警告

The debugger allows executing arbitrary Python code from the browser. It is protected by a pin, but still represents a major security risk. Do not run the development server or debugger in a production environment.
调试器允许从浏览器执行任意 Python 代码。它受到 PIN 保护,但仍代表重大的安全风险。请勿在生产环境中运行开发服务器或调试器。

To enable debug mode, use the --debug option.要启用调试模式,请使用 --debug 选项。

$ flask --app hello run --debug
 * Serving Flask app 'hello'
 * Debug mode: on
 * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: nnn-nnn-nnn

See also:  另见:

  • Development Server and Command Line Interface for information about running in debug mode.

    开发服务器和命令行界面,以获取有关以调试模式运行的信息。

  • Debugging Application Errors for information about using the built-in debugger and other debuggers.

    应用程序错误调试,以获取有关使用内置调试器和其他调试器的信息。

  • Logging and Handling Application Errors to log errors and display nice error pages.

    记录错误和显示漂亮的错误页面以记录错误并显示漂亮的错误页面。

HTML Escaping  HTML 转义 ¶

When returning HTML (the default response type in Flask), any user-provided values rendered in the output must be escaped to protect from injection attacks. HTML templates rendered with Jinja, introduced later, will do this automatically.
当返回 HTML(Flask 的默认响应类型)时,输出中渲染的任何用户提供的值都必须进行转义,以防止注入攻击。使用稍后介绍的 Jinja 渲染的 HTML 模板会自动完成此操作。

escape(), shown here, can be used manually. It is omitted in most examples for brevity, but you should always be aware of how you’re using untrusted data.escape() 可以手动使用。在大多数示例中为了简洁省略了它,但你应该始终意识到你在如何使用未信任的数据。

from markupsafe import escape

@app.route("/<name>")
def hello(name):
    return f"Hello, {escape(name)}!"

If a user managed to submit the name <script>alert("bad")</script>, escaping causes it to be rendered as text, rather than running the script in the user’s browser.如果用户提交了名称 <script>alert("bad")</script> ,转义会使其作为文本呈现,而不是在用户的浏览器中运行脚本。

<name> in the route captures a value from the URL and passes it to the view function. These variable rules are explained below.<name> 在路由中捕获 URL 中的一个值并将其传递给视图函数。这些可变规则将在下面解释。

Routing  路由 ¶

Modern web applications use meaningful URLs to help users. Users are more likely to like a page and come back if the page uses a meaningful URL they can remember and use to directly visit a page.
现代的网络应用使用有意义的 URL 来帮助用户。如果页面使用一个用户可以记住并直接访问该页面的有意义的 URL,用户更有可能喜欢这个页面并再次访问。

Use the route() decorator to bind a function to a URL.使用 route() 装饰器将一个函数绑定到一个 URL。

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

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

You can do more! You can make parts of the URL dynamic and attach multiple rules to a function.
你可以做更多!你可以让 URL 的部分动态,并将多个规则附加到一个函数上。

Variable Rules  可变规则 ¶

You can add variable sections to a URL by marking sections with <variable_name>. Your function then receives the <variable_name> as a keyword argument. Optionally, you can use a converter to specify the type of the argument like <converter:variable_name>.你可以通过标记部分为 <variable_name> 来向 URL 添加可变部分。你的函数随后会以关键字参数的形式接收 <variable_name> 。可选地,你可以使用转换器来指定参数的类型,如 <converter:variable_name>

from markupsafe import escape

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return f'User {escape(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 f'Post {post_id}'

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return f'Subpath {escape(subpath)}'

Converter types:  转换类型:

string(default) accepts any text without a slash (默认)接受任何不带斜杠的文本
intaccepts positive integers 接受正整数
floataccepts positive floating point values 接受正浮点数
pathlike string but also accepts slashes 类似 string ,但也可以接受斜杠
uuidaccepts UUID strings  接受 UUID 字符串

Unique URLs / Redirection Behavior

唯一 URL / 重定向行为 ¶

The following two rules differ in their use of a trailing slash.
以下两条规则在使用尾斜杠方面有所不同。

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

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

The canonical URL for the projects endpoint has a trailing slash. It’s similar to a folder in a file system. If you access the URL without a trailing slash (/projects), Flask redirects you to the canonical URL with the trailing slash (/projects/).projects 端点的规范 URL 带有尾斜杠。它类似于文件系统中的文件夹。如果您不使用尾斜杠访问该 URL( /projects ),Flask 会将您重定向到带有尾斜杠的规范 URL( /projects/ )。

The canonical URL for the about endpoint does not have a trailing slash. It’s similar to the pathname of a file. Accessing the URL with a trailing slash (/about/) produces a 404 “Not Found” error. This helps keep URLs unique for these resources, which helps search engines avoid indexing the same page twice.about 端点的规范 URL 不带有尾斜杠。它类似于文件的路径名。如果您使用尾斜杠访问该 URL( /about/ ),会返回 404“未找到”错误。这有助于保持这些资源的 URL 唯一性,从而帮助搜索引擎避免重复索引同一页面。

URL Building  URL 构建 ¶

To build a URL to a specific function, use the url_for() function. It accepts the name of the function as its first argument and any number of keyword arguments, each corresponding to a variable part of the URL rule. Unknown variable parts are appended to the URL as query parameters.要生成一个特定函数的 URL,请使用 url_for() 函数。它接受函数的名称作为第一个参数,并可以接受任意数量的关键字参数,每个参数对应 URL 规则中的一个可变部分。未知的可变部分将作为查询参数附加到 URL 中。

Why would you want to build URLs using the URL reversing function url_for() instead of hard-coding them into your templates?为什么你会选择使用 URL 反向解析函数 url_for() 来生成 URL,而不是直接将它们硬编码到模板中?

  1. Reversing is often more descriptive than hard-coding the URLs.

    反向解析通常比硬编码 URL 更具描述性。

  2. You can change your URLs in one go instead of needing to remember to manually change hard-coded URLs.

    你可以一次性更改你的 URL,而无需手动更改硬编码的 URL。

  3. URL building handles escaping of special characters transparently.

    URL 构建会透明地处理特殊字符的转义。

  4. The generated paths are always absolute, avoiding unexpected behavior of relative paths in browsers.

    生成的路径始终为绝对路径,避免了浏览器中相对路径的意外行为。

  5. If your application is placed outside the URL root, for example, in /myapplication instead of /, url_for() properly handles that for you.

    如果您的应用程序位于 URL 根之外,例如,在 /myapplication 而不是 /url_for()url_for() 会为您处理这种情况。

For example, here we use the test_request_context() method to try out url_for(). test_request_context() tells Flask to behave as though it’s handling a request even while we use a Python shell. See Context Locals.例如,这里我们使用 test_request_context() 方法来尝试 url_for()test_request_context() 告诉 Flask 即使我们在使用 Python shell,也要像处理请求一样进行处理。请参阅上下文局部变量。

from flask import url_for

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

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

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

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 Methods  HTTP 方法 ¶

Web applications use different HTTP methods when accessing URLs. You should familiarize yourself with the HTTP methods as you work with Flask. By default, a route only answers to GET requests. You can use the methods argument of the route() decorator to handle different HTTP methods.当访问 URL 时,Web 应用程序会使用不同的 HTTP 方法。当你使用 Flask 时,你应该熟悉这些 HTTP 方法。默认情况下,一个路由只会响应 GET 请求。你可以使用 route() 装饰器的 methods 参数来处理不同的 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()

The example above keeps all methods for the route within one function, which can be useful if each part uses some common data.
上面的例子将路由的所有方法都放在一个函数中,如果每个部分使用了一些共同的数据,这会很有用。

You can also separate views for different methods into different functions. Flask provides a shortcut for decorating such routes with get(), post(), etc. for each common HTTP method.你也可以将不同方法的视图分离到不同的函数中。Flask 提供了一个快捷方式,可以使用 get()post() 等装饰器为每个常见的 HTTP 方法装饰这些路由。

@app.get('/login')
def login_get():
    return show_the_login_form()

@app.post('/login')
def login_post():
    return do_the_login()

If GET is present, Flask automatically adds support for the HEAD method and handles HEAD requests according to the HTTP RFC. Likewise, OPTIONS is automatically implemented for you.如果存在 GET ,Flask 会自动添加对 HEAD 方法的支持,并根据 HTTP RFC 处理 HEAD 请求。同样, OPTIONS 也会自动为你实现。

Static Files  静态文件 ¶

Dynamic web applications also need static files. That’s usually where the CSS and JavaScript files are coming from. Ideally your web server is configured to serve them for you, but during development Flask can do that as well. Just create a folder called static in your package or next to your module and it will be available at /static on the application.动态网络应用程序还需要静态文件。通常,CSS 和 JavaScript 文件就来自这里。理想情况下,你的网络服务器会配置为提供这些文件,但在开发过程中,Flask 也可以做到这一点。只需在你的包中创建一个名为 static 的文件夹,或者在你的模块旁边创建一个,它将在应用程序中可用,路径为 /static

To generate URLs for static files, use the special 'static' endpoint name:生成静态文件的 URL,请使用特殊的 'static' 端点名称:

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

The file has to be stored on the filesystem as static/style.css.文件必须存储在文件系统中,路径为 static/style.css

Rendering Templates  渲染模板 ¶

Generating HTML from within Python is not fun, and actually pretty cumbersome because you have to do the HTML escaping on your own to keep the application secure. Because of that Flask configures the Jinja2 template engine for you automatically.在 Python 中生成 HTML 并不是一件有趣的事情,实际上相当繁琐,因为你必须自己进行 HTML 转义以保持应用程序的安全性。正因为如此,Flask 会自动为你配置 Jinja2 模板引擎。

Templates can be used to generate any type of text file. For web applications, you’ll primarily be generating HTML pages, but you can also generate markdown, plain text for emails, and anything else.
模板可以用来生成任何类型的文字文件。对于网络应用程序,你主要生成 HTML 页面,但你也可以生成 Markdown、电子邮件的纯文本,以及其他任何内容。

For a reference to HTML, CSS, and other web APIs, use the MDN Web Docs.对于 HTML、CSS 和其他 web API 的参考,请使用 MDN Web Docs。

To render a template you can use the render_template() method. All you have to do is provide the name of the template and the variables you want to pass to the template engine as keyword arguments. Here’s a simple example of how to render a template:要渲染一个模板,你可以使用 render_template() 方法。你只需要提供模板的名称和要传递给模板引擎的关键字参数即可。这里有一个简单的示例,说明如何渲染一个模板:

from flask import render_template

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

Flask will look for templates in the templates folder. So if your application is a module, this folder is next to that module, if it’s a package it’s actually inside your package:Flask 会在 templates 文件夹中查找模板。所以如果你的应用是一个模块,这个文件夹就在该模块旁边;如果你的应用是一个包,那么这个文件夹就在你的包里面。

Case 1: a module:  Case 1: 一个模块:

/application.py
/templates
    /hello.html

Case 2: a package:  包 2:一个包:

/application
    /__init__.py
    /templates
        /hello.html

For templates you can use the full power of Jinja2 templates. Head over to the official Jinja2 Template Documentation for more information.对于模板,您可以使用 Jinja2 模板的全部功能。请参阅官方 Jinja2 模板文档以获取更多信息。

Here is an example template:
这是一个示例模板:

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

Inside templates you also have access to the config, request, session and g [1] objects as well as the url_for() and get_flashed_messages() functions.在模板中,您还可以访问 configrequestsessiong [1] 对象,以及 url_for()get_flashed_messages() 函数。

Templates are especially useful if inheritance is used. If you want to know how that works, see Template Inheritance. Basically template inheritance makes it possible to keep certain elements on each page (like header, navigation and footer).如果使用了继承,模板特别有用。如果您想了解如何使用,请参阅模板继承。基本上,模板继承使得在每一页上保持某些元素(例如页头、导航和页脚)成为可能。

Automatic escaping is enabled, so if person contains HTML it will be escaped automatically. If you can trust a variable and you know that it will be safe HTML (for example because it came from a module that converts wiki markup to HTML) you can mark it as safe by using the Markup class or by using the |safe filter in the template. Head over to the Jinja 2 documentation for more examples.自动转义已启用,因此如果 person 包含 HTML,它将被自动转义。如果您可以信任一个变量,并且知道它是安全的 HTML(例如,因为它来自将维基标记转换为 HTML 的模块),您可以通过使用 Markup 类或在模板中使用 |safe 过滤器来标记它为安全。更多示例请参阅 Jinja 2 文档。

Here is a basic introduction to how the Markup class works:这里是对 Markup 类基本工作原理的一个介绍:

>>> from markupsafe import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup('<strong>Hello <blink>hacker</blink>!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup('<blink>hacker</blink>')
>>> Markup('<em>Marked up</em> » HTML').striptags()
'Marked up » HTML'

Changelog  变更日志

Changed in version 0.5: Autoescaping is no longer enabled for all templates. The following extensions for templates trigger autoescaping: .html, .htm, .xml, .xhtml. Templates loaded from a string will have autoescaping disabled.

Accessing Request Data  访问请求数据 ¶

For web applications it’s crucial to react to the data a client sends to the server. In Flask this information is provided by the global request object. If you have some experience with Python you might be wondering how that object can be global and how Flask manages to still be threadsafe. The answer is context locals:对于 Web 应用程序来说,响应客户端发送给服务器的数据至关重要。在 Flask 中,这些信息由全局 request 对象提供。如果你对 Python 有一定了解,可能会好奇这个对象是如何全局存在的,而 Flask 又是如何保持线程安全的。答案是上下文局部变量:

Context Locals  上下文局部变量

Insider Information  内部信息

If you want to understand how that works and how you can implement tests with context locals, read this section, otherwise just skip it.
如果你想了解它是如何工作的以及如何使用上下文局部变量实现测试,可以阅读这一部分,否则可以直接跳过。

Certain objects in Flask are global objects, but not of the usual kind. These objects are actually proxies to objects that are local to a specific context. What a mouthful. But that is actually quite easy to understand.
Flask 中的某些对象是全局对象,但不是通常意义上的全局对象。这些对象实际上是特定上下文中的对象的代理。听起来很复杂,但实际上很容易理解。

Imagine the context being the handling thread. A request comes in and the web server decides to spawn a new thread (or something else, the underlying object is capable of dealing with concurrency systems other than threads). When Flask starts its internal request handling it figures out that the current thread is the active context and binds the current application and the WSGI environments to that context (thread). It does that in an intelligent way so that one application can invoke another application without breaking.
想象一下,上下文是处理线程。一个请求进来,Web 服务器决定启动一个新的线程(或者其他东西,底层对象能够处理除了线程之外的并发系统)。当 Flask 开始内部请求处理时,它会确定当前线程是活动的上下文,并将当前的应用程序和 WSGI 环境绑定到该上下文中(线程)。它是以一种智能的方式进行的,这样一种应用程序可以调用另一种应用程序而不会出错。

So what does this mean to you? Basically you can completely ignore that this is the case unless you are doing something like unit testing. You will notice that code which depends on a request object will suddenly break because there is no request object. The solution is creating a request object yourself and binding it to the context. The easiest solution for unit testing is to use the test_request_context() context manager. In combination with the with statement it will bind a test request so that you can interact with it. Here is an example:那么这对你意味着什么呢?基本上,除非你在做单元测试之类的事情,否则你可以完全忽略这一点。你会发现,依赖于请求对象的代码会突然失效,因为没有请求对象。解决方法是自己创建一个请求对象,并将其绑定到上下文中。对于单元测试来说,最简单的解决方案是使用 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'

The other possibility is passing a whole WSGI environment to the request_context() method:另一种可能性是将整个 WSGI 环境传递给 request_context() 方法:

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

The Request Object  请求对象 ¶

The request object is documented in the API section and we will not cover it here in detail (see Request). Here is a broad overview of some of the most common operations. First of all you have to import it from the flask module:请求对象在 API 部分有详细文档,这里不会详细覆盖它(参见 Request )。下面是一些最常见的操作的简要概述。首先,你需要从 flask 模块导入它:

from flask import request

The current request method is available by using the method attribute. To access form data (data transmitted in a POST or PUT request) you can use the form attribute. Here is a full example of the two attributes mentioned above:当前请求方法可以通过使用 method 属性获取。要访问表单数据(在 POSTPUT 请求中传输的数据),可以使用 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)

What happens if the key does not exist in the form attribute? In that case a special KeyError is raised. You can catch it like a standard KeyError but if you don’t do that, a HTTP 400 Bad Request error page is shown instead. So for many situations you don’t have to deal with that problem.如果 form 属性中不存在该键会发生什么?在这种情况下,会抛出一个特殊的 KeyError 。你可以像处理标准的 KeyError 一样捕获它,但如果不去处理,会显示一个 HTTP 400 坏请求错误页面。因此,在许多情况下,你不需要处理这个问题。

To access parameters submitted in the URL (?key=value) you can use the args attribute:要访问在 URL 中提交的参数( ?key=value ),您可以使用 args 属性:

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

We recommend accessing URL parameters with get or by catching the KeyError because users might change the URL and presenting them a 400 bad request page in that case is not user friendly.我们建议使用 get 来访问 URL 参数,或者捕获 KeyError ,因为用户可能会更改 URL,在这种情况下向他们显示 400 错误页面并不友好。

For a full list of methods and attributes of the request object, head over to the Request documentation.若要查看 request 对象的所有方法和属性,请参阅 Request 文档。

File Uploads  文件上传 ¶

You can handle uploaded files with Flask easily. Just make sure not to forget to set the enctype="multipart/form-data" attribute on your HTML form, otherwise the browser will not transmit your files at all.使用 Flask 处理上传的文件非常简单。只是确保在 HTML 表单上设置了 enctype="multipart/form-data" 属性,否则浏览器将根本不传输文件。

Uploaded files are stored in memory or at a temporary location on the filesystem. You can access those files by looking at the files attribute on the request object. Each uploaded file is stored in that dictionary. It behaves just like a standard Python file object, but it also has a save() method that allows you to store that file on the filesystem of the server. Here is a simple example showing how that works:上传的文件会存储在内存中或文件系统的临时位置。你可以通过查看请求对象上的 files 属性来访问这些文件。每个上传的文件都存储在该字典中。它就像一个标准的 Python file 对象,但也有一个 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')
    ...

If you want to know how the file was named on the client before it was uploaded to your application, you can access the filename attribute. However please keep in mind that this value can be forged so never ever trust that value. If you want to use the filename of the client to store the file on the server, pass it through the secure_filename() function that Werkzeug provides for you:如果您想了解文件在上传到您的应用程序之前客户端是如何命名的,可以访问 filename 属性。但是请注意,这个值可能会被伪造,所以永远不要信任这个值。如果您想使用客户端的文件名在服务器上存储文件,请通过 Werkzeug 为您提供的 secure_filename() 函数对其进行处理:

from werkzeug.utils import secure_filename

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

For some better examples, see Uploading Files.对于更好的示例,请参阅上传文件。

Cookies

To access cookies you can use the cookies attribute. To set cookies you can use the set_cookie method of response objects. The cookies attribute of request objects is a dictionary with all the cookies the client transmits. If you want to use sessions, do not use the cookies directly but instead use the Sessions in Flask that add some security on top of cookies for you.要访问 cookies,可以使用 cookies 属性。要设置 cookies,可以使用响应对象的 set_cookie 方法。请求对象的 cookies 属性是一个字典,包含客户端传输的所有 cookies。如果你想使用会话,请不要直接使用 cookies,而是使用 Flask 提供的 Sessions,它会在 cookies 上为你添加一些安全功能。

Reading cookies:  读取 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:  存储 cookies:

from flask import make_response

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

Note that cookies are set on response objects. Since you normally just return strings from the view functions Flask will convert them into response objects for you. If you explicitly want to do that you can use the make_response() function and then modify it.请注意,cookie 是在响应对象中设置的。由于你通常只是从视图函数中返回字符串,Flask 会自动将它们转换为响应对象。如果你明确想要这样做,可以使用 make_response() 函数,然后对其进行修改。

Sometimes you might want to set a cookie at a point where the response object does not exist yet. This is possible by utilizing the Deferred Request Callbacks pattern.有时你可能希望在响应对象尚未存在的点设置一个 cookie。这可以通过利用延迟请求回调模式来实现。

For this also see About Responses.对于响应的更多信息,请参见关于响应。

Redirects and Errors  重定向和错误 ¶

To redirect a user to another endpoint, use the redirect() function; to abort a request early with an error code, use the abort() function:要将用户重定向到另一个端点,请使用 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()

This is a rather pointless example because a user will be redirected from the index to a page they cannot access (401 means access denied) but it shows how that works.
这是一个相当无意义的示例,因为用户会被重定向到一个他们无法访问的页面(401 表示访问被拒绝),但它展示了这是如何工作的。

By default a black and white error page is shown for each error code. If you want to customize the error page, you can use the errorhandler() decorator:默认情况下,会显示一个黑白的错误页面,针对每个错误代码。如果你想自定义错误页面,可以使用 errorhandler() 装饰器:

from flask import render_template

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

Note the 404 after the render_template() call. This tells Flask that the status code of that page should be 404 which means not found. By default 200 is assumed which translates to: all went well.在 render_template() 调用之后注意 404 。这告诉 Flask 那个页面的状态码应该是 404,即未找到。默认情况下,状态码假设为 200,这意味着一切正常。

See Handling Application Errors for more details.请参阅处理应用程序错误以获取更多详细信息。

About Responses  关于响应 ¶

The return value from a view function is automatically converted into a response object for you. If the return value is a string it’s converted into a response object with the string as response body, a 200 OK status code and a text/html mimetype. If the return value is a dict or list, jsonify() is called to produce a response. The logic that Flask applies to converting return values into response objects is as follows:视图函数的返回值会自动转换为响应对象。如果返回值是字符串,则会将其转换为具有字符串作为响应体、 200 OK 状态码和 text/html 媒体类型的响应对象。如果返回值是字典或列表,则会调用 jsonify() 生成响应。Flask 将返回值转换为响应对象的逻辑如下:

  1. If a response object of the correct type is returned it’s directly returned from the view.

    如果返回的是正确类型的响应对象,它将直接从视图中返回。

  2. If it’s a string, a response object is created with that data and the default parameters.

    如果是一个字符串,将创建一个响应对象,并使用默认参数。

  3. If it’s an iterator or generator returning strings or bytes, it is treated as a streaming response.

    如果它是返回字符串或字节的迭代器或生成器,它会被视为流式响应。

  4. If it’s a dict or list, a response object is created using jsonify().

    如果是字典或列表,将使用 jsonify() 创建一个响应对象。

  5. If a tuple is returned the items in the tuple can provide extra information. Such tuples have to be in the form (response, status), (response, headers), or (response, status, headers). The status value will override the status code and headers can be a list or dictionary of additional header values.

    如果返回的是元组,元组中的项可以提供额外信息。这样的元组必须是 (response, status)(response, headers)(response, status, headers) 的形式。 status 值将覆盖状态码, headers 可以是一个包含额外头信息的列表或字典。

  6. If none of that works, Flask will assume the return value is a valid WSGI application and convert that into a response object.

    如果以上都不适用,Flask 将假设返回值是一个有效的 WSGI 应用程序,并将其转换为响应对象。

If you want to get hold of the resulting response object inside the view you can use the make_response() function.如果您想在视图中获取结果响应对象,可以使用 make_response() 函数。

Imagine you have a view like this:
假设您有一个这样的视图:

from flask import render_template

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

You just need to wrap the return expression with make_response() and get the response object to modify it, then return it:您只需将返回表达式用 make_response() 包裹,并获取响应对象对其进行修改,然后返回它:

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

APIs with JSON  JSON 格式的 APIs ¶

A common response format when writing an API is JSON. It’s easy to get started writing such an API with Flask. If you return a dict or list from a view, it will be converted to a JSON response.编写 API 时常见的响应格式是 JSON。使用 Flask 编写这样的 API 很容易上手。如果你从一个视图返回一个 dictlist ,它将会被转换为 JSON 响应。

@app.route("/me")
def me_api():
    user = get_current_user()
    return {
        "username": user.username,
        "theme": user.theme,
        "image": url_for("user_image", filename=user.image),
    }

@app.route("/users")
def users_api():
    users = get_all_users()
    return [user.to_json() for user in users]

This is a shortcut to passing the data to the jsonify() function, which will serialize any supported JSON data type. That means that all the data in the dict or list must be JSON serializable.这是一条快捷方式,用于将数据传递给 jsonify() 函数,该函数会序列化任何支持的 JSON 数据类型。这意味着字典或列表中的所有数据都必须是可序列化的 JSON 数据。

For complex types such as database models, you’ll want to use a serialization library to convert the data to valid JSON types first. There are many serialization libraries and Flask API extensions maintained by the community that support more complex applications.
对于数据库模型等复杂类型,您需要使用序列化库将数据首先转换为有效的 JSON 类型。有许多由社区维护的序列化库和 Flask API 扩展程序,支持更复杂的应用程序。

Sessions  会话 ¶

In addition to the request object there is also a second object called session which allows you to store information specific to a user from one request to the next. This is implemented on top of cookies for you and signs the cookies cryptographically. What this means is that the user could look at the contents of your cookie but not modify it, unless they know the secret key used for signing.除了请求对象之外,还有一个名为 session 的对象,它允许您在一次请求到下一次请求之间存储特定于用户的信息。这在底层是基于 cookie 实现的,并且会加密 cookie。这意味着用户可以查看 cookie 的内容,但不能修改它,除非他们知道用于签名的密钥。

In order to use sessions you have to set a secret key. Here is how sessions work:
为了使用会话,您需要设置一个密钥。会话的工作方式如下:

from flask import session

# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'

@app.route('/')
def index():
    if 'username' in session:
        return f'Logged in as {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'))

How to generate good secret keys
如何生成好的密钥

A secret key should be as random as possible. Your operating system has ways to generate pretty random data based on a cryptographic random generator. Use the following command to quickly generate a value for Flask.secret_key (or SECRET_KEY):一个密钥应该尽可能随机。你的操作系统可以通过加密随机生成器生成相当随机的数据。使用以下命令快速生成 Flask.secret_key (或 SECRET_KEY ) 的值:

$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

A note on cookie-based sessions: Flask will take the values you put into the session object and serialize them into a cookie. If you are finding some values do not persist across requests, cookies are indeed enabled, and you are not getting a clear error message, check the size of the cookie in your page responses compared to the size supported by web browsers.
关于基于 cookie 的会话:Flask 会将你放入 session 对象中的值序列化为一个 cookie。如果你发现某些值在请求之间没有持久化,且已启用 cookie,且没有收到清晰的错误消息,请检查页面响应中的 cookie 大小与浏览器支持的大小是否一致。

Besides the default client-side based sessions, if you want to handle sessions on the server-side instead, there are several Flask extensions that support this.
除了默认的客户端基于会话之外,如果你想在服务器端处理会话,还有一些 Flask 扩展支持这一点。

Message Flashing  消息提示 ¶

Good applications and user interfaces are all about feedback. If the user does not get enough feedback they will probably end up hating the application. Flask provides a really simple way to give feedback to a user with the flashing system. The flashing system basically makes it possible to record a message at the end of a request and access it on the next (and only the next) request. This is usually combined with a layout template to expose the message.
良好的应用程序和用户界面都是关于反馈的。如果用户得不到足够的反馈,他们可能会讨厌这个应用程序。Flask 提供了一个非常简单的方式来通过闪存系统给用户反馈。闪存系统基本上可以在请求结束时记录一条消息,并在下一个(也是唯一一个)请求中访问它。这通常会与布局模板结合使用,以暴露这条消息。

To flash a message use the flash() method, to get hold of the messages you can use get_flashed_messages() which is also available in the templates. See Message Flashing for a full example.要显示一条消息,请使用 flash() 方法,要获取消息,您可以使用 get_flashed_messages() ,它在模板中也可用。参见消息闪存示例以获取完整示例。

Logging  日志记录 ¶

Changelog  变更日志

Added in version 0.3.

Sometimes you might be in a situation where you deal with data that should be correct, but actually is not. For example you may have some client-side code that sends an HTTP request to the server but it’s obviously malformed. This might be caused by a user tampering with the data, or the client code failing. Most of the time it’s okay to reply with 400 Bad Request in that situation, but sometimes that won’t do and the code has to continue working.有时你可能会遇到一种情况,需要处理的数据应该是正确的,但实际上却不是。例如,客户端代码可能会向服务器发送一个 HTTP 请求,但显然数据格式不正确。这种情况可能是用户篡改了数据,或者客户端代码出错导致的。大多数时候,在这种情况下回复 400 Bad Request 是可以的,但有时这不够,代码必须继续运行。

You may still want to log that something fishy happened. This is where loggers come in handy. As of Flask 0.3 a logger is preconfigured for you to use.
您可能仍然希望记录一些奇怪的事情发生了。这就是日志记录派上用场的地方。从 Flask 0.3 版本开始,已经为您预配置了一个日志记录器。

Here are some example log calls:
这是一些示例日志调用:

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

The attached logger is a standard logging Logger, so head over to the official logging docs for more information.附加的 logger 是一个标准的日志 Logger ,所以请参阅官方 logging 文档以获取更多信息。

See Handling Application Errors.查看处理应用程序错误。

Hooking in WSGI Middleware

钩入 WSGI 中间件 ¶

To add WSGI middleware to your Flask application, wrap the application’s wsgi_app attribute. For example, to apply Werkzeug’s ProxyFix middleware for running behind Nginx:要将 WSGI 中间件添加到你的 Flask 应用中,可以包裹应用的 wsgi_app 属性。例如,为了在 Nginx 后运行,应用 Werkzeug 的 ProxyFix 中间件:

from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)

Wrapping app.wsgi_app instead of app means that app still points at your Flask application, not at the middleware, so you can continue to use and configure app directly.Wrapping app.wsgi_app 而不是 app 意味着 app 仍然指向你的 Flask 应用程序,而不是中间件,因此你可以继续直接使用和配置 app

Using Flask Extensions  使用 Flask 扩展 ¶

Extensions are packages that help you accomplish common tasks. For example, Flask-SQLAlchemy provides SQLAlchemy support that makes it simple and easy to use with Flask.
扩展是帮助你完成常见任务的包。例如,Flask-SQLAlchemy 提供了 SQLAlchemy 支持,使得在 Flask 中使用它变得简单且容易。

For more on Flask extensions, see Extensions.要了解有关 Flask 扩展的更多信息,请参见扩展。

Deploying to a Web Server

部署到 Web 服务器 ¶

Ready to deploy your new Flask app? See Deploying to Production.准备好部署你的新 Flask 应用程序了吗?请参阅生产环境部署。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值