forked from orbit-oss/flask
Merge branch 'master' into celery-documentation
This commit is contained in:
commit
f13e3fc352
81 changed files with 1642 additions and 803 deletions
|
|
@ -6,7 +6,7 @@ Application Factories
|
|||
If you are already using packages and blueprints for your application
|
||||
(:ref:`blueprints`) there are a couple of really nice ways to further improve
|
||||
the experience. A common pattern is creating the application object when
|
||||
the blueprint is imported. But if you move the creation of this object,
|
||||
the blueprint is imported. But if you move the creation of this object
|
||||
into a function, you can then create multiple instances of this app later.
|
||||
|
||||
So why would you want to do this?
|
||||
|
|
@ -60,7 +60,7 @@ Factories & Extensions
|
|||
It's preferable to create your extensions and app factories so that the
|
||||
extension object does not initially get bound to the application.
|
||||
|
||||
Using `Flask-SQLAlchemy <http://pythonhosted.org/Flask-SQLAlchemy/>`_,
|
||||
Using `Flask-SQLAlchemy <http://flask-sqlalchemy.pocoo.org/>`_,
|
||||
as an example, you should not do something along those lines::
|
||||
|
||||
def create_app(config_filename):
|
||||
|
|
|
|||
|
|
@ -3,71 +3,43 @@
|
|||
Deferred Request Callbacks
|
||||
==========================
|
||||
|
||||
One of the design principles of Flask is that response objects are created
|
||||
and passed down a chain of potential callbacks that can modify them or
|
||||
replace them. When the request handling starts, there is no response
|
||||
object yet. It is created as necessary either by a view function or by
|
||||
some other component in the system.
|
||||
One of the design principles of Flask is that response objects are created and
|
||||
passed down a chain of potential callbacks that can modify them or replace
|
||||
them. When the request handling starts, there is no response object yet. It is
|
||||
created as necessary either by a view function or by some other component in
|
||||
the system.
|
||||
|
||||
But what happens if you want to modify the response at a point where the
|
||||
response does not exist yet? A common example for that would be a
|
||||
before-request function that wants to set a cookie on the response object.
|
||||
What happens if you want to modify the response at a point where the response
|
||||
does not exist yet? A common example for that would be a
|
||||
:meth:`~flask.Flask.before_request` callback that wants to set a cookie on the
|
||||
response object.
|
||||
|
||||
One way is to avoid the situation. Very often that is possible. For
|
||||
instance you can try to move that logic into an after-request callback
|
||||
instead. Sometimes however moving that code there is just not a very
|
||||
pleasant experience or makes code look very awkward.
|
||||
One way is to avoid the situation. Very often that is possible. For instance
|
||||
you can try to move that logic into a :meth:`~flask.Flask.after_request`
|
||||
callback instead. However, sometimes moving code there makes it more
|
||||
more complicated or awkward to reason about.
|
||||
|
||||
As an alternative possibility you can attach a bunch of callback functions
|
||||
to the :data:`~flask.g` object and call them at the end of the request.
|
||||
This way you can defer code execution from anywhere in the application.
|
||||
|
||||
|
||||
The Decorator
|
||||
-------------
|
||||
|
||||
The following decorator is the key. It registers a function on a list on
|
||||
the :data:`~flask.g` object::
|
||||
|
||||
from flask import 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
|
||||
|
||||
|
||||
Calling the Deferred
|
||||
--------------------
|
||||
|
||||
Now you can use the `after_this_request` decorator to mark a function to
|
||||
be called at the end of the request. But we still need to call them. For
|
||||
this the following function needs to be registered as
|
||||
:meth:`~flask.Flask.after_request` callback::
|
||||
|
||||
@app.after_request
|
||||
def call_after_request_callbacks(response):
|
||||
for callback in getattr(g, 'after_request_callbacks', ()):
|
||||
callback(response)
|
||||
return response
|
||||
|
||||
|
||||
A Practical Example
|
||||
-------------------
|
||||
As an alternative, you can use :func:`~flask.after_this_request` to register
|
||||
callbacks that will execute after only the current request. This way you can
|
||||
defer code execution from anywhere in the application, based on the current
|
||||
request.
|
||||
|
||||
At any time during a request, we can register a function to be called at the
|
||||
end of the request. For example you can remember the current language of the
|
||||
user in a cookie in the before-request function::
|
||||
end of the request. For example you can remember the current language of the
|
||||
user in a cookie in a :meth:`~flask.Flask.before_request` callback::
|
||||
|
||||
from flask import request
|
||||
from flask import request, after_this_request
|
||||
|
||||
@app.before_request
|
||||
def detect_user_language():
|
||||
language = request.cookies.get('user_lang')
|
||||
|
||||
if language is None:
|
||||
language = guess_language_from_request()
|
||||
|
||||
# when the response exists, set a cookie with the language
|
||||
@after_this_request
|
||||
def remember_language(response):
|
||||
response.set_cookie('user_lang', language)
|
||||
|
||||
g.language = language
|
||||
|
|
|
|||
|
|
@ -174,4 +174,4 @@ the code without having to run ``install`` again after each change.
|
|||
|
||||
|
||||
.. _pip: https://pypi.python.org/pypi/pip
|
||||
.. _Setuptools: https://pythonhosted.org/setuptools
|
||||
.. _Setuptools: https://pypi.python.org/pypi/setuptools
|
||||
|
|
|
|||
|
|
@ -47,37 +47,53 @@ even if the application behaves correctly:
|
|||
Error Handlers
|
||||
--------------
|
||||
|
||||
An error handler is a function, just like a view function, but it is
|
||||
called when an error happens and is passed that error. The error is most
|
||||
likely a :exc:`~werkzeug.exceptions.HTTPException`, but in one case it
|
||||
can be a different error: a handler for internal server errors will be
|
||||
passed other exception instances as well if they are uncaught.
|
||||
An error handler is a function that returns a response when a type of error is
|
||||
raised, similar to how a view is a function that returns a response when a
|
||||
request URL is matched. It is passed the instance of the error being handled,
|
||||
which is most likely a :exc:`~werkzeug.exceptions.HTTPException`. An error
|
||||
handler for "500 Internal Server Error" will be passed uncaught exceptions in
|
||||
addition to explicit 500 errors.
|
||||
|
||||
An error handler is registered with the :meth:`~flask.Flask.errorhandler`
|
||||
decorator and the error code of the exception. Keep in mind that Flask
|
||||
will *not* set the error code for you, so make sure to also provide the
|
||||
HTTP status code when returning a response.
|
||||
decorator or the :meth:`~flask.Flask.register_error_handler` method. A handler
|
||||
can be registered for a status code, like 404, or for an exception class.
|
||||
|
||||
Please note that if you add an error handler for "500 Internal Server
|
||||
Error", Flask will not trigger it if it's running in Debug mode.
|
||||
The status code of the response will not be set to the handler's code. Make
|
||||
sure to provide the appropriate HTTP status code when returning a response from
|
||||
a handler.
|
||||
|
||||
Here an example implementation for a "404 Page Not Found" exception::
|
||||
A handler for "500 Internal Server Error" will not be used when running in
|
||||
debug mode. Instead, the interactive debugger will be shown.
|
||||
|
||||
Here is an example implementation for a "404 Page Not Found" exception::
|
||||
|
||||
from flask import render_template
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
# note that we set the 404 status explicitly
|
||||
return render_template('404.html'), 404
|
||||
|
||||
When using the :ref:`application factory pattern <app-factories>`::
|
||||
|
||||
from flask import Flask, render_template
|
||||
|
||||
def page_not_found(e):
|
||||
return render_template('404.html'), 404
|
||||
|
||||
def create_app(config_filename):
|
||||
app = Flask(__name__)
|
||||
app.register_error_handler(404, page_not_found)
|
||||
return app
|
||||
|
||||
An example template might be this:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Page Not Found{% endblock %}
|
||||
{% block body %}
|
||||
<h1>Page Not Found</h1>
|
||||
<p>What you were looking for is just not there.
|
||||
<p><a href="{{ url_for('index') }}">go somewhere nice</a>
|
||||
{% endblock %}
|
||||
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Page Not Found{% endblock %}
|
||||
{% block body %}
|
||||
<h1>Page Not Found</h1>
|
||||
<p>What you were looking for is just not there.
|
||||
<p><a href="{{ url_for('index') }}">go somewhere nice</a>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -49,5 +49,5 @@ web server's documentation.
|
|||
See also
|
||||
--------
|
||||
|
||||
* The `Favicon <http://en.wikipedia.org/wiki/Favicon>`_ article on
|
||||
* The `Favicon <https://en.wikipedia.org/wiki/Favicon>`_ article on
|
||||
Wikipedia
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ specific upload folder and displays a file to the user. Let's look at the
|
|||
bootstrapping code for our application::
|
||||
|
||||
import os
|
||||
from flask import Flask, request, redirect, url_for
|
||||
from flask import Flask, flash, request, redirect, url_for
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
UPLOAD_FOLDER = '/path/to/the/uploads'
|
||||
|
|
@ -58,7 +58,7 @@ the file and redirects the user to the URL for the uploaded file::
|
|||
return redirect(request.url)
|
||||
file = request.files['file']
|
||||
# if user does not select file, browser also
|
||||
# submit a empty part without filename
|
||||
# submit an empty part without filename
|
||||
if file.filename == '':
|
||||
flash('No selected file')
|
||||
return redirect(request.url)
|
||||
|
|
@ -72,8 +72,8 @@ the file and redirects the user to the URL for the uploaded file::
|
|||
<title>Upload new File</title>
|
||||
<h1>Upload new File</h1>
|
||||
<form method=post enctype=multipart/form-data>
|
||||
<p><input type=file name=file>
|
||||
<input type=submit value=Upload>
|
||||
<input type=file name=file>
|
||||
<input type=submit value=Upload>
|
||||
</form>
|
||||
'''
|
||||
|
||||
|
|
@ -181,4 +181,4 @@ applications dealing with uploads, there is also a Flask extension called
|
|||
blacklisting of extensions and more.
|
||||
|
||||
.. _jQuery: https://jquery.com/
|
||||
.. _Flask-Uploads: http://pythonhosted.org/Flask-Uploads/
|
||||
.. _Flask-Uploads: https://pythonhosted.org/Flask-Uploads/
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ this::
|
|||
login.html
|
||||
...
|
||||
|
||||
If you find yourself stuck on something, feel free
|
||||
to take a look at the source code for this example.
|
||||
You'll find `the full src for this example here`_.
|
||||
|
||||
Simple Packages
|
||||
---------------
|
||||
|
||||
|
|
@ -61,7 +65,7 @@ that tells Flask where to find the application instance::
|
|||
export FLASK_APP=yourapplication
|
||||
|
||||
If you are outside of the project directory make sure to provide the exact
|
||||
path to your application directory. Similiarly you can turn on "debug
|
||||
path to your application directory. Similarly you can turn on "debug
|
||||
mode" with this environment variable::
|
||||
|
||||
export FLASK_DEBUG=true
|
||||
|
|
@ -130,6 +134,7 @@ You should then end up with something like that::
|
|||
|
||||
|
||||
.. _working-with-modules:
|
||||
.. _the full src for this example here: https://github.com/pallets/flask/tree/master/examples/patterns/largerapp
|
||||
|
||||
Working with Blueprints
|
||||
-----------------------
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ if you want to get started quickly.
|
|||
You can download `Flask-SQLAlchemy`_ from `PyPI
|
||||
<https://pypi.python.org/pypi/Flask-SQLAlchemy>`_.
|
||||
|
||||
.. _Flask-SQLAlchemy: http://pythonhosted.org/Flask-SQLAlchemy/
|
||||
.. _Flask-SQLAlchemy: http://flask-sqlalchemy.pocoo.org/
|
||||
|
||||
|
||||
Declarative
|
||||
|
|
@ -108,9 +108,9 @@ Querying is simple as well:
|
|||
>>> User.query.filter(User.name == 'admin').first()
|
||||
<User u'admin'>
|
||||
|
||||
.. _SQLAlchemy: http://www.sqlalchemy.org/
|
||||
.. _SQLAlchemy: https://www.sqlalchemy.org/
|
||||
.. _declarative:
|
||||
http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/
|
||||
https://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/
|
||||
|
||||
Manual Object Relational Mapping
|
||||
--------------------------------
|
||||
|
|
@ -135,7 +135,7 @@ Here is an example :file:`database.py` module for your application::
|
|||
def init_db():
|
||||
metadata.create_all(bind=engine)
|
||||
|
||||
As for the declarative approach you need to close the session after
|
||||
As in the declarative approach, you need to close the session after
|
||||
each request or application context shutdown. Put this into your
|
||||
application module::
|
||||
|
||||
|
|
@ -215,4 +215,4 @@ You can also pass strings of SQL statements to the
|
|||
(1, u'admin', u'admin@localhost')
|
||||
|
||||
For more information about SQLAlchemy, head over to the
|
||||
`website <http://www.sqlalchemy.org/>`_.
|
||||
`website <https://www.sqlalchemy.org/>`_.
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
Using SQLite 3 with Flask
|
||||
=========================
|
||||
|
||||
In Flask you can easily implement the opening of database connections on
|
||||
demand and closing them when the context dies (usually at the end of the
|
||||
In Flask you can easily implement the opening of database connections on
|
||||
demand and closing them when the context dies (usually at the end of the
|
||||
request).
|
||||
|
||||
Here is a simple example of how you can use SQLite 3 with Flask::
|
||||
|
|
@ -71,7 +71,7 @@ Now in each request handling function you can access `g.db` to get the
|
|||
current open database connection. To simplify working with SQLite, a
|
||||
row factory function is useful. It is executed for every result returned
|
||||
from the database to convert the result. For instance, in order to get
|
||||
dictionaries instead of tuples, this could be inserted into the ``get_db``
|
||||
dictionaries instead of tuples, this could be inserted into the ``get_db``
|
||||
function we created above::
|
||||
|
||||
def make_dicts(cursor, row):
|
||||
|
|
@ -102,15 +102,15 @@ This would use Row objects rather than dicts to return the results of queries. T
|
|||
|
||||
Additionally, it is a good idea to provide a query function that combines
|
||||
getting the cursor, executing and fetching the results::
|
||||
|
||||
|
||||
def query_db(query, args=(), one=False):
|
||||
cur = get_db().execute(query, args)
|
||||
rv = cur.fetchall()
|
||||
cur.close()
|
||||
return (rv[0] if rv else None) if one else rv
|
||||
|
||||
This handy little function, in combination with a row factory, makes
|
||||
working with the database much more pleasant than it is by just using the
|
||||
This handy little function, in combination with a row factory, makes
|
||||
working with the database much more pleasant than it is by just using the
|
||||
raw cursor and connection objects.
|
||||
|
||||
Here is how you can use it::
|
||||
|
|
@ -131,7 +131,7 @@ To pass variable parts to the SQL statement, use a question mark in the
|
|||
statement and pass in the arguments as a list. Never directly add them to
|
||||
the SQL statement with string formatting because this makes it possible
|
||||
to attack the application using `SQL Injections
|
||||
<http://en.wikipedia.org/wiki/SQL_injection>`_.
|
||||
<https://en.wikipedia.org/wiki/SQL_injection>`_.
|
||||
|
||||
Initial Schemas
|
||||
---------------
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ forms.
|
|||
fun. You can get it from `PyPI
|
||||
<https://pypi.python.org/pypi/Flask-WTF>`_.
|
||||
|
||||
.. _Flask-WTF: http://pythonhosted.org/Flask-WTF/
|
||||
.. _Flask-WTF: https://flask-wtf.readthedocs.io/en/stable/
|
||||
|
||||
The Forms
|
||||
---------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue