from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!'
启动Server:
$ export FLASK_APP=hello.py $ flask run * Running on http://127.0.0.1:5000/
或者:
$ export FLASK_APP=hello.py $ python -m flask run * Running on http://127.0.0.1:5000/
在 Windows 中,用 set 替代 export 来设置环境变量。
在 Powershell中,设置环境变量如下:
$env:FLASK_APP="hello.py"
若要监听所有公共IP地址:
flask run --host=0.0.0.0
启动Debug模式:
$ export FLASK_DEBUG=1 $ flask run
This does the following things:
- it activates the debugger
- it activates the automatic reloader
- it enables the debug mode on the Flask application.
(在 window 中,用 set 替代 export 来设置环境变量)
路由URL:
the route()
decorator is used to bind a function to a URL. Here are some basic examples:
@app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello, World'
To add variable parts to a URL you can mark these special sections as <variable_name>
. Such a part is then passed as a keyword argument to your function. Optionally a converter can be used by specifying a rule with <converter:variable_name>
. Here are some nice examples:
@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
The following converters exist:
”String“ - accepts any text without a slash (the default)
”int“ - accepts integers
”float“ - like int but for floating point values
”path“ - like the default but also accepts slashes
”any“ - matches one of the items provided
”uuid“ - accepts UUID strings
Unique URLs / Redirection Behavior
@app.route('/projects/') def projects(): return 'The project page' @app.route('/about') def about(): return 'The about page'
Though they look rather similar, they differ in their use of the trailing slash in the URLdefinition. In the first case, the canonical URL for the projects endpoint has a trailing slash. In that sense, it is similar to a folder on a filesystem. Accessing it without a trailing slash will cause Flask to redirect to the canonical URL with the trailing slash.
In the second case, however, the URL is defined without a trailing slash, rather like the pathname of a file on UNIX-like systems. Accessing the URL with a trailing slash will produce a 404 “Not Found” error.
This behavior allows relative URLs to continue working even if the trailing slash is omitted, consistent with how Apache and other servers work. Also, the URLs will stay unique, which helps search engines avoid indexing the same page twice.
URL Building
To build a URL to a specific function you can use the url_for()
function. It accepts the name of the function as first argument and a number of keyword arguments, each corresponding to the variable part of the URL rule. Unknown variable parts are appended to the URL as query parameters.
>>> from flask import Flask, url_for >>> app = Flask(__name__) >>> @app.route('/') ... def index(): pass ... >>> @app.route('/login') ... def login(): pass ... >>> @app.route('/user/<username>') ... def profile(username): pass ... >>> 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 Method
HTTP (the protocol web applications are speaking) knows different methods for accessing URLs. By default, a route only answers to GET
requests, but that can be changed by providing the methods argument to the route()
decorator. Here are some examples:
from flask import request @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': do_the_login() else: show_the_login_form()
The following methods are very common:
- The browser tells the server to just get the information stored on that page and send it. This is probably the most common method.
-
The browser tells the server to get the information, but it is only interested in the
headers, not the content of the page. An application is supposed to handle that as if a
GET
request was received but to not deliver the actual content. In Flask you don’t have to deal with that at all, the underlying Werkzeug library handles that for you. - The browser tells the server that it wants to post some new information to that URL and that the server must ensure the data is stored and only stored once. This is how HTML forms usually transmit data to the server.
-
Similar to
POST
but the server might trigger the store procedure multiple times by overwriting the old values more than once. Now you might be asking why this is useful, but there are some good reasons to do it this way. Consider that the connection is lost during transmission: in this situation a system between the browser and the server might receive the request safely a second time without breaking things. WithPOST
that would not be possible because it must only be triggered once. - Remove the information at the given location.
- Provides a quick way for a client to figure out which methods are supported by this URL. Starting with Flask 0.6, this is implemented for you automatically.
GET
HEAD
POST
PUT
DELETE
OPTIONS
Now the interesting part is that in HTML4 and XHTML1, the only methods a form can submit to the server are GET
and POST
. But with JavaScript and future HTML standards you can use the other methods as well. Furthermore HTTP has become quite popular lately and browsers are no longer the only clients that are using HTTP. For instance, many revision control systems use it.
Static Files
ust create a folder called static
in your package or next to your module and it will be available at /static
on the application.
To generate URLs for static files, use the special 'static'
endpoint name:
url_for('static', filename='style.css')
The file has to be stored on the filesystem as static/style.css
.
Rendering Templates
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:
from flask import render_template @app.route('/hello/') @app.route('/hello/<name>') def hello(name=None): return render_template('hello.html', name=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:
Case 1: a module:
/application.py /templates /hello.html
Case 2: a package:
/application /__init__.py /templates /hello.html
For templates you can use the full power of Jinja2 templates.
Here is an example template:
<!doctype html> <title>Hello from Flask</title> {% if name %} <h1>Hello {{ name }}!</h1> {% else %} <h1>Hello, World!</h1> {% endif %}
Inside templates you also have access to the request
, session
and g
objects as well as the get_flashed_messages()
function.
Templates are especially useful if inheritance is used. Basically template inheritance makes it possible to keep certain elements on each page (like header, navigation and footer).
Automatic escaping is enabled, so if name 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.
Here is a basic introduction to how the Markup
class works:
>>> from flask import Markup >>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>' Markup(u'<strong>Hello <blink>hacker</blink>!</strong>') >>> Markup.escape('<blink>hacker</blink>') Markup(u'<blink>hacker</blink>') >>> Markup('<em>Marked up</em> » HTML').striptags() u'Marked up \xbb HTML'
Accessing Request Data
Context Locals
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.
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.
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:
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:
from flask import request with app.request_context(environ): assert request.method == 'POST'
The Request Object
from flask import 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' # the code below is executed if the request method # was GET or the credentials were invalid return render_template('login.html', error=error)
To access parameters submitted in the URL (?key=value
) you can use the args
attribute:
searchword = request.args.get('key', '')
File Uploads
You can handle uploaded files with Flask easily. Just make sure not to forget to set theenctype="multipart/form-data"
attribute on your HTML form, otherwise the browser will not transmit your files at all.
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') ...
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)) ...
Cookies
Read 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
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.
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:
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()
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:
from flask import render_template @app.errorhandler(404) def page_not_found(error): return render_template('page_not_found.html'), 404
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. The logic that Flask applies to converting return values into response objects is as follows:
- If a response object of the correct type is returned it’s directly returned from the view.
- If it’s a string, a response object is created with that data and the default parameters.
- If a tuple is returned the items in the tuple can provide extra information. Such tuples have to be in the form
(response, status, headers)
or(response, headers)
where at least one item has to be in the tuple. The status value will override the status code and headers can be a list or dictionary of additional header values. - If none of that works, Flask will assume the return value is a valid WSGI application and convert that into a response object.
If you want to get hold of the resulting response object inside the view you can use themake_response()
function.
Imagine you have a view like this:
@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:
@app.errorhandler(404) def not_found(error): resp = make_response(render_template('error.html'), 404) resp.headers['X-Something'] = 'A value' return resp
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.
In order to use sessions you have to set a secret key. Here is how sessions work:
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 action="" 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'
The escape()
mentioned here does escaping for you if you are not using the template engine (as in this example).
How to generate the good secret keys:
The problem with random is that it’s hard to judge what is truly random. And a secret key should be as random as possible. Your operating system has ways to generate pretty random stuff based on a cryptographic random generator which can be used to get such a key:
>>> import os >>> os.urandom(24) '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
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.
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.
To flash a message use the flash()
method, to get hold of the messages you can useget_flashed_messages()
which is also available in the templates.
Logging
app.logger.debug('A value for debugging') app.logger.warning('A warning occurred (%d apples)', 42) app.logger.error('An error occurred')
Hooking in WSGI Middlewares
If you want to add a WSGI middleware to your application you can wrap the internal WSGI application. For example if you want to use one of the middlewares from the Werkzeug package to work around bugs in lighttpd, you can do it like this:
from werkzeug.contrib.fixers import LighttpdCGIRootFix app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
Using Flask Extensions
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.
For more on Flask extensions, have a look at Flask Extensions.
Deploying to a Web Server
Ready to deploy your new Flask app? Go to Deployment Options.