Browse Source

Merge branch 'master' into module-support

pull/1638/head
Armin Ronacher 15 years ago
parent
commit
13933eeaf8
  1. 69
      docs/patterns/caching.rst
  2. 2
      docs/patterns/index.rst
  3. 93
      docs/patterns/viewdecorators.rst

69
docs/patterns/caching.rst

@ -0,0 +1,69 @@
.. _caching-pattern:
Caching
=======
When your application runs slow, throw some caches in. Well, at least
it's the easiest way to speed up things. What does a cache do? Say you
have a function that takes some time to complete but the results would
still be good enough if they were 5 minutes old. So then the idea is that
you actually put the result of that calculation into a cache for some
time.
Flask itself does not provide caching for you, but Werkzeug, one of the
libraries it is based on, has some very basic cache support. It supports
multiple cache backends, normally you want to use a memcached server.
Setting up a Cache
------------------
You create a cache object once and keep it around, similar to how
:class:`~flask.Flask` objects are created. If you are using the
development server you can create a
:class:`~werkzeug.contrib.cache.SimpleCache` object, that one is a simple
cache that keeps the item stored in the memory of the Python interpreter::
from werkzeug.contrib.cache import SimpleCache
cache = SimpleCache()
If you want to use memcached, make sure to have one of the memcache modules
supported (you get them from `PyPI <http://pypi.python.org/>`_) and a
memcached server running somewhere. This is how you connect to such an
memcached server then::
from werkzeug.contrib.cache import MemcachedCache
cache = MemcachedCache(['127.0.0.1:11211'])
If you are using appengine, you can connect to the appengine memcache
server easily::
from werkzeug.contrib.cache import GAEMemcachedCache
cache = GAEMemcachedCache()
Using a Cache
-------------
Now how can one use such a cache? There are two very important
operations: :meth:`~werkzeug.contrib.cache.BaseCache.get` and
:meth:`~werkzeug.contrib.cache.BaseCache.set`. This is how to use them:
To get an item from the cache call
:meth:`~werkzeug.contrib.cache.BaseCache.get` with a string as key name.
If something is in the cache, it is returned. Otherwise that function
will return `None`::
rv = cache.get('my-item')
To add items to the cache, use the :meth:`~werkzeug.contrib.cache.BaseCache.set`
method instead. The first argument is the key and the second the value
that should be set. Also a timeout can be provided after which the cache
will automatically remove item.
Here a full example how this looks like normally::
def get_my_item():
rv = cache.get('my-item')
if rv is None:
rv = calculate_value()
cache.set('my-item', rv, timeout=5 * 60)
return rv

2
docs/patterns/index.rst

@ -17,6 +17,8 @@ end of the request, the database connection is closed again.
sqlite3
sqlalchemy
fileuploads
caching
viewdecorators
wtforms
templateinheritance
flashing

93
docs/patterns/viewdecorators.rst

@ -0,0 +1,93 @@
View Decorators
===============
Python has a really interesting feature called function decorators. This
allow some really neat things for web applications. Because each view in
Flask is a function decorators can be used to inject additional
functionality to one or more functions. The :meth:`~flask.Flask.route`
decorator is the one you probably used already. But there are use cases
for implementing your own decorator. For instance, imagine you have a
view that should only be used by people that are logged in to. If a user
goes to the site and is not logged in, he should be redirected to the
login page. This is a good example of a use case where a decorator is an
excellent solution.
Login Required Decorator
------------------------
So let's implement such a decorator. A decorator is a function that
returns a function. Pretty simple actually. The only thing you have to
keep in mind when implementing something like this is to update the
`__name__`, `__module__` and some other attributes of a function. This is
often forgotten, but you don't have to do that by hand, there is a
function for that that is used like a decorator (:func:`functools.wraps`).
This example assumes that the login page is called ``'login'`` and that
the current user is stored as `g.user` and `None` if there is no-one
logged in::
from functools import wraps
from flask import g, request, redirect, url_for
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for('login', next=request.url))
return f(*args, **kwargs)
return decorated_function
So how would you use that decorator now? Apply it as innermost decorator
to a view function. When applying further decorators, always remember
that the :meth:`~flask.Flask.route` decorator is the outermost::
@app.route('/secret_page')
@login_required
def secret_page():
pass
Caching Decorator
-----------------
Imagine you have a view function that does an expensive calculation and
because of that you would like to cache the generated results for a
certain amount of time. A decorator would be nice for that. We're
assuming you have set up a cache like mentioned in :ref:`caching-pattern`.
Here an example cache function. It generates the cache key from a
specific prefix (actually a format string) and the current path of the
request. Notice that we are using a function that first creates the
decorator that then decorates the function. Sounds awful? Unfortunately
it is a little bit more complex, but the code should still be
straightforward to read.
The decorated function will then work as follows
1. get the unique cache key for the current request base on the current
path.
2. get the value for that key from the cache. If the cache returned
something we will return that value.
3. otherwise the original function is called and the return value is
stored in the cache for the timeout provided (by default 5 minutes).
Here the code::
from functools import wraps
from flask import request
def cached(timeout=5 * 60, key='view/%s'):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
cache_key = key % request.path
rv = cache.get(cache_key)
if rv is not None:
return rv
rv = f(*args, **kwargs)
cache.set(cache_key, rv, timeout=timeout)
return rv
return decorated_function
return decorator
Notice that this assumes an instanciated `cache` object is available, see
:ref:`caching-pattern` for more information.
Loading…
Cancel
Save