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 | ||||
| 
 | ||||
| Flask knows a concept known as “blueprints” which can greatly simplify how | ||||
| large applications work.  A blueprint is an object works similar to an | ||||
| actual :class:`Flask` application object, but it is not actually an | ||||
| application.  Rather it is the blueprint of how to create an application. | ||||
| Think of it like that: you might want to have an application that has a | ||||
| wiki.  So what you can do is creating the blueprint for a wiki and then | ||||
| let the application assemble the wiki on the application object. | ||||
| Flask uses a concept of *blueprints* for making application components and | ||||
| supporting common patterns within an application or across applications. | ||||
| Blueprints can greatly simplify how large applications work and provide a | ||||
| central means for Flask extensions to register operations on applications. | ||||
| A :class:`Blueprint` object works similarly to a :class:`Flask` | ||||
| application object, but it is not actually an application.  Rather it is a | ||||
| *blueprint* of how to construct or extend an application. | ||||
| 
 | ||||
| Why Blueprints? | ||||
| --------------- | ||||
| 
 | ||||
| Why have blueprints and not multiple application objects?  The utopia of | ||||
| 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 in Flask are intended for these cases: | ||||
| 
 | ||||
| Blueprints do not necessarily have to implement applications.  They could | ||||
| only provide filters for templates, static files, templates or similar | ||||
| things.  They share the same config as the application and can change the | ||||
| application as necessary when being registered. | ||||
| * Factor an application into a set of blueprints.  This is ideal for | ||||
|   larger applications; a project could instantiate an application object, | ||||
|   initialize several extensions, and register a collection of blueprints. | ||||
| * 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 | ||||
| without having to destroy the whole application object. | ||||
| 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 basic concept of blueprints is that they record operations that should | ||||
| be executed when the blueprint is registered on the application.  However | ||||
| additionally each time a request gets dispatched to a view that was | ||||
| declared to a blueprint Flask will remember that the request was | ||||
| dispatched to that blueprint.  That way it's easier to generate URLs from | ||||
| one endpoint to another in the same module. | ||||
| The basic concept of blueprints is that they record operations to execute | ||||
| when registered on an application.  Flask associates view functions with | ||||
| blueprints when dispatching requests and generating URLs from one endpoint | ||||
| to another. | ||||
| 
 | ||||
| My First Blueprint | ||||
| ------------------ | ||||
|  |  | |||
|  | @ -174,13 +174,14 @@ It's easy to see the behavior from the command line: | |||
| 
 | ||||
| >>> app = Flask(__name__) | ||||
| >>> @app.teardown_request | ||||
| ... def after_request(exception=None): | ||||
| ...     print 'after request' | ||||
| ...  | ||||
| ... def teardown_request(exception=None): | ||||
| ...     print 'this runs after request' | ||||
| ... | ||||
| >>> ctx = app.test_request_context() | ||||
| >>> ctx.push() | ||||
| >>> ctx.pop() | ||||
| after request | ||||
| this runs after request | ||||
| >>> | ||||
| 
 | ||||
| .. _notes-on-proxies: | ||||
| 
 | ||||
|  |  | |||
|  | @ -124,8 +124,8 @@ class Blueprint(_PackageBoundObject): | |||
|             deferred(state) | ||||
| 
 | ||||
|     def route(self, rule, **options): | ||||
|         """Like :meth:`Flask.route` but for a module.  The endpoint for the | ||||
|         :func:`url_for` function is prefixed with the name of the module. | ||||
|         """Like :meth:`Flask.route` but for a blueprint.  The endpoint for the | ||||
|         :func:`url_for` function is prefixed with the name of the blueprint. | ||||
|         """ | ||||
|         def decorator(f): | ||||
|             self.add_url_rule(rule, f.__name__, f, **options) | ||||
|  | @ -133,15 +133,15 @@ class Blueprint(_PackageBoundObject): | |||
|         return decorator | ||||
| 
 | ||||
|     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 | ||||
|         the :func:`url_for` function is prefixed with the name of the module. | ||||
|         """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 blueprint. | ||||
|         """ | ||||
|         self.record(lambda s: | ||||
|             s.add_url_rule(rule, endpoint, view_func, **options)) | ||||
| 
 | ||||
|     def endpoint(self, endpoint): | ||||
|         """Like :meth:`Flask.endpoint` but for a module.  This does not | ||||
|         prefix the endpoint with the module name, this has to be done | ||||
|         """Like :meth:`Flask.endpoint` but for a blueprint.  This does not | ||||
|         prefix the endpoint with the blueprint name, this has to be done | ||||
|         explicitly by the user of this method.  If the endpoint is prefixed | ||||
|         with a `.` it will be registered to the current blueprint, otherwise | ||||
|         it's an application independent endpoint. | ||||
|  | @ -154,9 +154,9 @@ class Blueprint(_PackageBoundObject): | |||
|         return decorator | ||||
| 
 | ||||
|     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 | ||||
|         that module. | ||||
|         that blueprint. | ||||
|         """ | ||||
|         self.record_once(lambda s: s.app.before_request_funcs | ||||
|             .setdefault(self.name, []).append(f)) | ||||
|  | @ -164,48 +164,48 @@ class Blueprint(_PackageBoundObject): | |||
| 
 | ||||
|     def before_app_request(self, f): | ||||
|         """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 | ||||
|             .setdefault(None, []).append(f)) | ||||
|         return 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 | ||||
|         that module. | ||||
|         that blueprint. | ||||
|         """ | ||||
|         self.record_once(lambda s: s.app.after_request_funcs | ||||
|             .setdefault(self.name, []).append(f)) | ||||
|         return f | ||||
| 
 | ||||
|     def after_app_request(self, f): | ||||
|         """Like :meth:`Flask.after_request` but for a module.  Such a function | ||||
|         is executed after each request, even if outside of the module. | ||||
|         """Like :meth:`Flask.after_request` but for a blueprint.  Such a function | ||||
|         is executed after each request, even if outside of the blueprint. | ||||
|         """ | ||||
|         self.record_once(lambda s: s.app.after_request_funcs | ||||
|             .setdefault(None, []).append(f)) | ||||
|         return f | ||||
| 
 | ||||
|     def context_processor(self, f): | ||||
|         """Like :meth:`Flask.context_processor` but for a module.  This | ||||
|         function is only executed for requests handled by a module. | ||||
|         """Like :meth:`Flask.context_processor` but for a blueprint.  This | ||||
|         function is only executed for requests handled by a blueprint. | ||||
|         """ | ||||
|         self.record_once(lambda s: s.app.template_context_processors | ||||
|             .setdefault(self.name, []).append(f)) | ||||
|         return f | ||||
| 
 | ||||
|     def app_context_processor(self, f): | ||||
|         """Like :meth:`Flask.context_processor` but for a module.  Such a | ||||
|         function is executed each request, even if outside of the module. | ||||
|         """Like :meth:`Flask.context_processor` but for a blueprint.  Such a | ||||
|         function is executed each request, even if outside of the blueprint. | ||||
|         """ | ||||
|         self.record_once(lambda s: s.app.template_context_processors | ||||
|             .setdefault(None, []).append(f)) | ||||
|         return f | ||||
| 
 | ||||
|     def app_errorhandler(self, code): | ||||
|         """Like :meth:`Flask.errorhandler` but for a module.  This | ||||
|         handler is used for all requests, even if outside of the module. | ||||
|         """Like :meth:`Flask.errorhandler` but for a blueprint.  This | ||||
|         handler is used for all requests, even if outside of the blueprint. | ||||
|         """ | ||||
|         def decorator(f): | ||||
|             self.record_once(lambda s: s.app.errorhandler(code)(f)) | ||||
|  | @ -222,7 +222,7 @@ class Blueprint(_PackageBoundObject): | |||
|         return 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 | ||||
|         in place. | ||||
|         """ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue