Merge pull request #3391 from pallets/explain-escape
explain escape at top of quickstart
This commit is contained in:
commit
4bceeccfff
1 changed files with 50 additions and 49 deletions
|
|
@ -3,48 +3,59 @@
|
||||||
Quickstart
|
Quickstart
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Eager to get started? This page gives a good introduction to Flask. It
|
Eager to get started? This page gives a good introduction to Flask.
|
||||||
assumes you already have Flask installed. If you do not, head over to the
|
Follow :doc:`installation` to set up a project and install Flask first.
|
||||||
:ref:`installation` section.
|
|
||||||
|
|
||||||
|
|
||||||
A Minimal Application
|
A Minimal Application
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
A minimal Flask application looks something like this::
|
A minimal Flask application looks something like this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
from markupsafe import escape
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def hello_world():
|
def hello_world():
|
||||||
return 'Hello, World!'
|
return f"<p>Hello, {escape(name)}!</p>"
|
||||||
|
|
||||||
So what did that code do?
|
So what did that code do?
|
||||||
|
|
||||||
1. First we imported the :class:`~flask.Flask` class. An instance of this
|
1. First we imported the :class:`~flask.Flask` class. An instance of
|
||||||
class will be our WSGI application.
|
this class will be our WSGI application.
|
||||||
2. Next we create an instance of this class. The first argument is the name of
|
2. Next we create an instance of this class. The first argument is the
|
||||||
the application's module or package. If you are using a single module (as
|
name of the application's module or package. ``__name__`` is a
|
||||||
in this example), you should use ``__name__`` because depending on if it's
|
convenient shortcut for this that is appropriate for most cases.
|
||||||
started as application or imported as module the name will be different
|
This is needed so that Flask knows where to look for resources such
|
||||||
(``'__main__'`` versus the actual import name). This is needed so that
|
as templates and static files.
|
||||||
Flask knows where to look for templates, static files, and so on. For more
|
3. We then use the :meth:`~flask.Flask.route` decorator to tell Flask
|
||||||
information have a look at the :class:`~flask.Flask` documentation.
|
what URL should trigger our function.
|
||||||
3. We then use the :meth:`~flask.Flask.route` decorator to tell Flask what URL
|
4. The function returns the message we want to display in the user's
|
||||||
should trigger our function.
|
browser. The default content type is HTML, so HTML in the string
|
||||||
4. The function is given a name which is also used to generate URLs for that
|
will be rendered by the browser.
|
||||||
particular function, and returns the message we want to display in the
|
|
||||||
user's browser.
|
|
||||||
|
|
||||||
Just save it as :file:`hello.py` or something similar. Make sure to not call
|
.. note:: HTML escaping
|
||||||
|
|
||||||
|
When returning HTML (the default response type in Flask), any user
|
||||||
|
input rendered in the output must be escaped to protect from
|
||||||
|
injection attacks. HTML templates in Jinja, introduced later, will
|
||||||
|
do this automatically. :func:`~markupsafe.escape`, shown above, can
|
||||||
|
be used manually. It's omitted for brevity in the examples below.
|
||||||
|
|
||||||
|
Save it as :file:`hello.py` or something similar. Make sure to not call
|
||||||
your application :file:`flask.py` because this would conflict with Flask
|
your application :file:`flask.py` because this would conflict with Flask
|
||||||
itself.
|
itself.
|
||||||
|
|
||||||
To run the application you can either use the :command:`flask` command or
|
To run the application, use the :command:`flask` command or
|
||||||
python's ``-m`` switch with Flask. Before you can do that you need
|
:command:`python -m flask`. Before you can do that you need
|
||||||
to tell your terminal the application to work with by exporting the
|
to tell your terminal the application to work with by exporting the
|
||||||
``FLASK_APP`` environment variable::
|
``FLASK_APP`` environment variable:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
$ export FLASK_APP=hello.py
|
$ export FLASK_APP=hello.py
|
||||||
$ flask run
|
$ flask run
|
||||||
|
|
@ -59,12 +70,6 @@ And on PowerShell::
|
||||||
|
|
||||||
PS C:\path\to\app> $env:FLASK_APP = "hello.py"
|
PS C:\path\to\app> $env:FLASK_APP = "hello.py"
|
||||||
|
|
||||||
Alternatively you can use :command:`python -m flask`::
|
|
||||||
|
|
||||||
$ export FLASK_APP=hello.py
|
|
||||||
$ python -m flask run
|
|
||||||
* Running on http://127.0.0.1:5000/
|
|
||||||
|
|
||||||
This launches a very simple builtin server, which is good enough for testing
|
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
|
but probably not what you want to use in production. For deployment options see
|
||||||
:ref:`deployment`.
|
:ref:`deployment`.
|
||||||
|
|
@ -203,17 +208,17 @@ of the argument like ``<converter:variable_name>``. ::
|
||||||
@app.route('/user/<username>')
|
@app.route('/user/<username>')
|
||||||
def show_user_profile(username):
|
def show_user_profile(username):
|
||||||
# show the user profile for that user
|
# show the user profile for that user
|
||||||
return 'User %s' % escape(username)
|
return f'User {username}'
|
||||||
|
|
||||||
@app.route('/post/<int:post_id>')
|
@app.route('/post/<int:post_id>')
|
||||||
def show_post(post_id):
|
def show_post(post_id):
|
||||||
# show the post with the given id, the id is an integer
|
# show the post with the given id, the id is an integer
|
||||||
return 'Post %d' % post_id
|
return f'Post {post_id}'
|
||||||
|
|
||||||
@app.route('/path/<path:subpath>')
|
@app.route('/path/<path:subpath>')
|
||||||
def show_subpath(subpath):
|
def show_subpath(subpath):
|
||||||
# show the subpath after /path/
|
# show the subpath after /path/
|
||||||
return 'Subpath %s' % escape(subpath)
|
return f'Subpath {subpath}'
|
||||||
|
|
||||||
Converter types:
|
Converter types:
|
||||||
|
|
||||||
|
|
@ -281,9 +286,7 @@ Python shell. See :ref:`context-locals`.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from flask import Flask, escape, url_for
|
from flask import url_for
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
|
|
@ -295,7 +298,7 @@ Python shell. See :ref:`context-locals`.
|
||||||
|
|
||||||
@app.route('/user/<username>')
|
@app.route('/user/<username>')
|
||||||
def profile(username):
|
def profile(username):
|
||||||
return '{}\'s profile'.format(escape(username))
|
return f'{username}\'s profile'
|
||||||
|
|
||||||
with app.test_request_context():
|
with app.test_request_context():
|
||||||
print(url_for('index'))
|
print(url_for('index'))
|
||||||
|
|
@ -416,12 +419,12 @@ 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
|
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
|
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 to HTML) you can mark it as safe by using the
|
||||||
:class:`~jinja2.Markup` class or by using the ``|safe`` filter in the
|
:class:`~markupsafe.Markup` class or by using the ``|safe`` filter in the
|
||||||
template. Head over to the Jinja 2 documentation for more examples.
|
template. Head over to the Jinja 2 documentation for more examples.
|
||||||
|
|
||||||
Here is a basic introduction to how the :class:`~jinja2.Markup` class works::
|
Here is a basic introduction to how the :class:`~jinja2.Markup` class works::
|
||||||
|
|
||||||
>>> from flask import Markup
|
>>> from markupsafe import Markup
|
||||||
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
|
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
|
||||||
Markup(u'<strong>Hello <blink>hacker</blink>!</strong>')
|
Markup(u'<strong>Hello <blink>hacker</blink>!</strong>')
|
||||||
>>> Markup.escape('<blink>hacker</blink>')
|
>>> Markup.escape('<blink>hacker</blink>')
|
||||||
|
|
@ -495,8 +498,6 @@ test request so that you can interact with it. Here is an example::
|
||||||
The other possibility is passing a whole WSGI environment to the
|
The other possibility is passing a whole WSGI environment to the
|
||||||
:meth:`~flask.Flask.request_context` method::
|
:meth:`~flask.Flask.request_context` method::
|
||||||
|
|
||||||
from flask import request
|
|
||||||
|
|
||||||
with app.request_context(environ):
|
with app.request_context(environ):
|
||||||
assert request.method == 'POST'
|
assert request.method == 'POST'
|
||||||
|
|
||||||
|
|
@ -582,7 +583,6 @@ of the client to store the file on the server, pass it through the
|
||||||
:func:`~werkzeug.utils.secure_filename` function that
|
:func:`~werkzeug.utils.secure_filename` function that
|
||||||
Werkzeug provides for you::
|
Werkzeug provides for you::
|
||||||
|
|
||||||
from flask import request
|
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
@app.route('/upload', methods=['GET', 'POST'])
|
@app.route('/upload', methods=['GET', 'POST'])
|
||||||
|
|
@ -706,6 +706,8 @@ you can use the :func:`~flask.make_response` function.
|
||||||
|
|
||||||
Imagine you have a view like this::
|
Imagine you have a view like this::
|
||||||
|
|
||||||
|
from flask import render_template
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def not_found(error):
|
def not_found(error):
|
||||||
return render_template('error.html'), 404
|
return render_template('error.html'), 404
|
||||||
|
|
@ -714,6 +716,8 @@ You just need to wrap the return expression with
|
||||||
:func:`~flask.make_response` and get the response object to modify it, then
|
:func:`~flask.make_response` and get the response object to modify it, then
|
||||||
return it::
|
return it::
|
||||||
|
|
||||||
|
from flask import make_response
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def not_found(error):
|
def not_found(error):
|
||||||
resp = make_response(render_template('error.html'), 404)
|
resp = make_response(render_template('error.html'), 404)
|
||||||
|
|
@ -747,6 +751,8 @@ more complex applications.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
from flask import jsonify
|
||||||
|
|
||||||
@app.route("/users")
|
@app.route("/users")
|
||||||
def users_api():
|
def users_api():
|
||||||
users = get_all_users()
|
users = get_all_users()
|
||||||
|
|
@ -768,9 +774,7 @@ unless they know the secret key used for signing.
|
||||||
In order to use sessions you have to set a secret key. Here is how
|
In order to use sessions you have to set a secret key. Here is how
|
||||||
sessions work::
|
sessions work::
|
||||||
|
|
||||||
from flask import Flask, session, redirect, url_for, escape, request
|
from flask import session
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
# Set the secret key to some random bytes. Keep this really secret!
|
# Set the secret key to some random bytes. Keep this really secret!
|
||||||
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
|
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
|
||||||
|
|
@ -778,7 +782,7 @@ sessions work::
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
if 'username' in session:
|
if 'username' in session:
|
||||||
return 'Logged in as %s' % escape(session['username'])
|
return f'Logged in as {session["username"]}'
|
||||||
return 'You are not logged in'
|
return 'You are not logged in'
|
||||||
|
|
||||||
@app.route('/login', methods=['GET', 'POST'])
|
@app.route('/login', methods=['GET', 'POST'])
|
||||||
|
|
@ -799,9 +803,6 @@ sessions work::
|
||||||
session.pop('username', None)
|
session.pop('username', None)
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
The :func:`~flask.escape` mentioned here does escaping for you if you are
|
|
||||||
not using the template engine (as in this example).
|
|
||||||
|
|
||||||
.. admonition:: How to generate good secret keys
|
.. admonition:: How to generate good secret keys
|
||||||
|
|
||||||
A secret key should be as random as possible. Your operating system has
|
A secret key should be as random as possible. Your operating system has
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue