Browse Source

Merge branch 'blueprints' of github.com:mitsuhiko/flask into blueprints

pull/262/head
Armin Ronacher 14 years ago
parent
commit
5ca333e9b7
  1. 65
      docs/blueprints.rst
  2. 7
      docs/reqcontext.rst
  3. 40
      flask/blueprints.py

65
docs/blueprints.rst

@ -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 * Factor an application into a set of blueprints. This is ideal for
the right tool for every case. Having different applications means having larger applications; a project could instantiate an application object,
different configs. Applications are also separated on the WSGI layer initialize several extensions, and register a collection of blueprints.
which is a lot lower level than the level that Flask usually operates on * Register a blueprint on an application at a URL prefix and/or subdomain.
where you have request and response objects. Paremeters in the URL prefix/subdomain become common view arguments
(with defaults) across all view functions in the blueprint.
Blueprints do not necessarily have to implement applications. They could * Register a blueprint multiple times on an application with different URL
only provide filters for templates, static files, templates or similar rules.
things. They share the same config as the application and can change the * Provide template filters, static files, templates, and other utilities
application as necessary when being registered. through blueprints. A blueprint does not have to implement applications
or view functions.
The downside is that you cannot unregister a blueprint once application * Register a blueprint on an application for any of these cases when
without having to destroy the whole application object. initializing a Flask extension.
A blueprint in Flask is not a pluggable app because it is not actually an
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
------------------ ------------------

7
docs/reqcontext.rst

@ -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:

40
flask/blueprints.py

@ -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…
Cancel
Save