mirror of https://github.com/pallets/flask.git
Merge branch 'blueprints' of github.com:mitsuhiko/flask into blueprints
This commit is contained in:
commit
5ca333e9b7
|
|
@ -5,42 +5,51 @@ Modular Applications with Blueprints
|
||||||
|
|
||||||
.. versionadded:: 0.7
|
.. versionadded:: 0.7
|
||||||
|
|
||||||
Flask knows a concept known as “blueprints” which can greatly simplify how
|
Flask uses a concept of *blueprints* for making application components and
|
||||||
large applications work. A blueprint is an object works similar to an
|
supporting common patterns within an application or across applications.
|
||||||
actual :class:`Flask` application object, but it is not actually an
|
Blueprints can greatly simplify how large applications work and provide a
|
||||||
application. Rather it is the blueprint of how to create an application.
|
central means for Flask extensions to register operations on applications.
|
||||||
Think of it like that: you might want to have an application that has a
|
A :class:`Blueprint` object works similarly to a :class:`Flask`
|
||||||
wiki. So what you can do is creating the blueprint for a wiki and then
|
application object, but it is not actually an application. Rather it is a
|
||||||
let the application assemble the wiki on the application object.
|
*blueprint* of how to construct or extend an application.
|
||||||
|
|
||||||
Why Blueprints?
|
Why Blueprints?
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Why have blueprints and not multiple application objects? The utopia of
|
Blueprints in Flask are intended for these cases:
|
||||||
pluggable applications are different WSGI applications and merging them
|
|
||||||
together somehow. You can do that (see :ref:`app-dispatch`) but it's not
|
|
||||||
the right tool for every case. Having different applications means having
|
|
||||||
different configs. Applications are also separated on the WSGI layer
|
|
||||||
which is a lot lower level than the level that Flask usually operates on
|
|
||||||
where you have request and response objects.
|
|
||||||
|
|
||||||
Blueprints do not necessarily have to implement applications. They could
|
* Factor an application into a set of blueprints. This is ideal for
|
||||||
only provide filters for templates, static files, templates or similar
|
larger applications; a project could instantiate an application object,
|
||||||
things. They share the same config as the application and can change the
|
initialize several extensions, and register a collection of blueprints.
|
||||||
application as necessary when being registered.
|
* Register a blueprint on an application at a URL prefix and/or subdomain.
|
||||||
|
Paremeters in the URL prefix/subdomain become common view arguments
|
||||||
|
(with defaults) across all view functions in the blueprint.
|
||||||
|
* Register a blueprint multiple times on an application with different URL
|
||||||
|
rules.
|
||||||
|
* Provide template filters, static files, templates, and other utilities
|
||||||
|
through blueprints. A blueprint does not have to implement applications
|
||||||
|
or view functions.
|
||||||
|
* Register a blueprint on an application for any of these cases when
|
||||||
|
initializing a Flask extension.
|
||||||
|
|
||||||
The downside is that you cannot unregister a blueprint once application
|
A blueprint in Flask is not a pluggable app because it is not actually an
|
||||||
without having to destroy the whole application object.
|
application -- it's a set of operations which can be registered on an
|
||||||
|
application, even multiple times. Why not have multiple application
|
||||||
|
objects? You can do that (see :ref:`app-dispatch`), but your applications
|
||||||
|
will have separate configs and will be managed at the WSGI layer.
|
||||||
|
|
||||||
|
Blueprints instead provide separation at the Flask level, share
|
||||||
|
application config, and can change an application object as necessary with
|
||||||
|
being registered. The downside is that you cannot unregister a blueprint
|
||||||
|
once application without having to destroy the whole application object.
|
||||||
|
|
||||||
The Concept of Blueprints
|
The Concept of Blueprints
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
The basic concept of blueprints is that they record operations that should
|
The basic concept of blueprints is that they record operations to execute
|
||||||
be executed when the blueprint is registered on the application. However
|
when registered on an application. Flask associates view functions with
|
||||||
additionally each time a request gets dispatched to a view that was
|
blueprints when dispatching requests and generating URLs from one endpoint
|
||||||
declared to a blueprint Flask will remember that the request was
|
to another.
|
||||||
dispatched to that blueprint. That way it's easier to generate URLs from
|
|
||||||
one endpoint to another in the same module.
|
|
||||||
|
|
||||||
My First Blueprint
|
My First Blueprint
|
||||||
------------------
|
------------------
|
||||||
|
|
|
||||||
|
|
@ -174,13 +174,14 @@ It's easy to see the behavior from the command line:
|
||||||
|
|
||||||
>>> app = Flask(__name__)
|
>>> app = Flask(__name__)
|
||||||
>>> @app.teardown_request
|
>>> @app.teardown_request
|
||||||
... def after_request(exception=None):
|
... def teardown_request(exception=None):
|
||||||
... print 'after request'
|
... print 'this runs after request'
|
||||||
...
|
...
|
||||||
>>> ctx = app.test_request_context()
|
>>> ctx = app.test_request_context()
|
||||||
>>> ctx.push()
|
>>> ctx.push()
|
||||||
>>> ctx.pop()
|
>>> ctx.pop()
|
||||||
after request
|
this runs after request
|
||||||
|
>>>
|
||||||
|
|
||||||
.. _notes-on-proxies:
|
.. _notes-on-proxies:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,8 @@ class Blueprint(_PackageBoundObject):
|
||||||
deferred(state)
|
deferred(state)
|
||||||
|
|
||||||
def route(self, rule, **options):
|
def route(self, rule, **options):
|
||||||
"""Like :meth:`Flask.route` but for a module. The endpoint for the
|
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
|
||||||
:func:`url_for` function is prefixed with the name of the module.
|
:func:`url_for` function is prefixed with the name of the blueprint.
|
||||||
"""
|
"""
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
self.add_url_rule(rule, f.__name__, f, **options)
|
self.add_url_rule(rule, f.__name__, f, **options)
|
||||||
|
|
@ -133,15 +133,15 @@ class Blueprint(_PackageBoundObject):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
|
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
|
||||||
"""Like :meth:`Flask.add_url_rule` but for a module. The endpoint for
|
"""Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
|
||||||
the :func:`url_for` function is prefixed with the name of the module.
|
the :func:`url_for` function is prefixed with the name of the blueprint.
|
||||||
"""
|
"""
|
||||||
self.record(lambda s:
|
self.record(lambda s:
|
||||||
s.add_url_rule(rule, endpoint, view_func, **options))
|
s.add_url_rule(rule, endpoint, view_func, **options))
|
||||||
|
|
||||||
def endpoint(self, endpoint):
|
def endpoint(self, endpoint):
|
||||||
"""Like :meth:`Flask.endpoint` but for a module. This does not
|
"""Like :meth:`Flask.endpoint` but for a blueprint. This does not
|
||||||
prefix the endpoint with the module name, this has to be done
|
prefix the endpoint with the blueprint name, this has to be done
|
||||||
explicitly by the user of this method. If the endpoint is prefixed
|
explicitly by the user of this method. If the endpoint is prefixed
|
||||||
with a `.` it will be registered to the current blueprint, otherwise
|
with a `.` it will be registered to the current blueprint, otherwise
|
||||||
it's an application independent endpoint.
|
it's an application independent endpoint.
|
||||||
|
|
@ -154,9 +154,9 @@ class Blueprint(_PackageBoundObject):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def before_request(self, f):
|
def before_request(self, f):
|
||||||
"""Like :meth:`Flask.before_request` but for a module. This function
|
"""Like :meth:`Flask.before_request` but for a blueprint. This function
|
||||||
is only executed before each request that is handled by a function of
|
is only executed before each request that is handled by a function of
|
||||||
that module.
|
that blueprint.
|
||||||
"""
|
"""
|
||||||
self.record_once(lambda s: s.app.before_request_funcs
|
self.record_once(lambda s: s.app.before_request_funcs
|
||||||
.setdefault(self.name, []).append(f))
|
.setdefault(self.name, []).append(f))
|
||||||
|
|
@ -164,48 +164,48 @@ class Blueprint(_PackageBoundObject):
|
||||||
|
|
||||||
def before_app_request(self, f):
|
def before_app_request(self, f):
|
||||||
"""Like :meth:`Flask.before_request`. Such a function is executed
|
"""Like :meth:`Flask.before_request`. Such a function is executed
|
||||||
before each request, even if outside of a module.
|
before each request, even if outside of a blueprint.
|
||||||
"""
|
"""
|
||||||
self.record_once(lambda s: s.app.before_request_funcs
|
self.record_once(lambda s: s.app.before_request_funcs
|
||||||
.setdefault(None, []).append(f))
|
.setdefault(None, []).append(f))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def after_request(self, f):
|
def after_request(self, f):
|
||||||
"""Like :meth:`Flask.after_request` but for a module. This function
|
"""Like :meth:`Flask.after_request` but for a blueprint. This function
|
||||||
is only executed after each request that is handled by a function of
|
is only executed after each request that is handled by a function of
|
||||||
that module.
|
that blueprint.
|
||||||
"""
|
"""
|
||||||
self.record_once(lambda s: s.app.after_request_funcs
|
self.record_once(lambda s: s.app.after_request_funcs
|
||||||
.setdefault(self.name, []).append(f))
|
.setdefault(self.name, []).append(f))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def after_app_request(self, f):
|
def after_app_request(self, f):
|
||||||
"""Like :meth:`Flask.after_request` but for a module. Such a function
|
"""Like :meth:`Flask.after_request` but for a blueprint. Such a function
|
||||||
is executed after each request, even if outside of the module.
|
is executed after each request, even if outside of the blueprint.
|
||||||
"""
|
"""
|
||||||
self.record_once(lambda s: s.app.after_request_funcs
|
self.record_once(lambda s: s.app.after_request_funcs
|
||||||
.setdefault(None, []).append(f))
|
.setdefault(None, []).append(f))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def context_processor(self, f):
|
def context_processor(self, f):
|
||||||
"""Like :meth:`Flask.context_processor` but for a module. This
|
"""Like :meth:`Flask.context_processor` but for a blueprint. This
|
||||||
function is only executed for requests handled by a module.
|
function is only executed for requests handled by a blueprint.
|
||||||
"""
|
"""
|
||||||
self.record_once(lambda s: s.app.template_context_processors
|
self.record_once(lambda s: s.app.template_context_processors
|
||||||
.setdefault(self.name, []).append(f))
|
.setdefault(self.name, []).append(f))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def app_context_processor(self, f):
|
def app_context_processor(self, f):
|
||||||
"""Like :meth:`Flask.context_processor` but for a module. Such a
|
"""Like :meth:`Flask.context_processor` but for a blueprint. Such a
|
||||||
function is executed each request, even if outside of the module.
|
function is executed each request, even if outside of the blueprint.
|
||||||
"""
|
"""
|
||||||
self.record_once(lambda s: s.app.template_context_processors
|
self.record_once(lambda s: s.app.template_context_processors
|
||||||
.setdefault(None, []).append(f))
|
.setdefault(None, []).append(f))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def app_errorhandler(self, code):
|
def app_errorhandler(self, code):
|
||||||
"""Like :meth:`Flask.errorhandler` but for a module. This
|
"""Like :meth:`Flask.errorhandler` but for a blueprint. This
|
||||||
handler is used for all requests, even if outside of the module.
|
handler is used for all requests, even if outside of the blueprint.
|
||||||
"""
|
"""
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
self.record_once(lambda s: s.app.errorhandler(code)(f))
|
self.record_once(lambda s: s.app.errorhandler(code)(f))
|
||||||
|
|
@ -222,7 +222,7 @@ class Blueprint(_PackageBoundObject):
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def url_defaults(self, f):
|
def url_defaults(self, f):
|
||||||
"""Callback function for URL defaults for this module. It's called
|
"""Callback function for URL defaults for this blueprint. It's called
|
||||||
with the endpoint and values and should update the values passed
|
with the endpoint and values and should update the values passed
|
||||||
in place.
|
in place.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue