Skip to content

Commit

Permalink
Updated the documentation to show how to set cookies for not yet exis…
Browse files Browse the repository at this point in the history
…ting responses
  • Loading branch information
mitsuhiko committed Sep 5, 2011
1 parent 7331ae3 commit b40af3c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
73 changes: 73 additions & 0 deletions docs/patterns/deferredcallbacks.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.. _deferred-callbacks:

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.

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.

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.

As an alternative possibility you can attach a bunch of callback functions
to the :data:`~flask.g` object and call then 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', ()):
response = callback(response)
return response


A Practical Example
-------------------

Now we can easily at any point in time register a function to be called at
the end of this particular request. For example you can remember the
current language of the user in a cookie in the before-request function::

from flask import request

@app.before_request
def detect_user_language():
language = request.cookies.get('user_lang')
if language is None:
language = guess_language_from_request()
@after_this_request
def remember_language(response):
response.set_cookie('user_lang', language)
g.language = language
1 change: 1 addition & 0 deletions docs/patterns/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ Snippet Archives <http://flask.pocoo.org/snippets/>`_.
mongokit
favicon
streaming
cookies
4 changes: 4 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,10 @@ just return strings from the view functions Flask will convert them into
response objects for you. If you explicitly want to do that you can use
the :meth:`~flask.make_response` function and then modify it.

Sometimes you might want to set a cookie at a point where the response
object does not exist yet. This is possible by utilizing the
:ref:`deferred-callbacks` pattern.

For this also see :ref:`about-responses`.

Redirects and Errors
Expand Down

0 comments on commit b40af3c

Please sign in to comment.