Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed bug in cache_page decorator #64

Merged
merged 4 commits into from
Mar 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,11 @@ You can also use django's caching middlewares
``django.middleware.cache.UpdateCacheMiddleware`` and
``FetchFromCacheMiddleware`` like you already do. But to make them aware of
flavours, you need to add
``django_mobile.cache.middleware.CacheFlavourMiddleware`` as second last item
in the ``MIDDLEWARE_CLASSES`` settings, right before
``FetchFromCacheMiddleware``.
``django_mobile.cache.middleware.FetchFromCacheFlavourMiddleware`` item before standard Django ``FetchFromCacheMiddleware``
in the ``MIDDLEWARE_CLASSES`` settings and ``django_mobile.cache.middleware.UpdateCacheFlavourMiddleware`` before
``django_mobile.cache.middleware.UpdateCacheMiddleware`` correspondingly.

It is necessary to split the usage of ``CacheMiddleware`` because some additional work should be done on request and response *before* standard caching behavior and that is not possible while using two complete middlewares in either order

Reference
=========
Expand Down Expand Up @@ -194,16 +195,19 @@ Reference
to ``DEFAULT_MOBILE_FLAVOUR`` settings value in case.

``django_mobile.cache.cache_page``
Same as django's ``cache_page`` decorator but applies ``vary_on_flavour``
before the view is decorated with
``django.views.decorators.cache.cache_page``.
Same as django's ``cache_page`` decorator, but wraps the view into
additional decorators before and after that. Makes it possible to serve multiple
flavours without getting into trouble with django's caching that doesn't
know about flavours.

``django_mobile.cache.vary_on_flavour``
A decorator created from the ``CacheFlavourMiddleware`` middleware.
``django_mobile.cache.vary_on_flavour_fetch`` ``django_mobile.cache.vary_on_flavour_update``
Decorators created from the ``FetchFromCacheFlavourMiddleware`` and ``UpdateCacheFlavourMiddleware`` middleware.

``django_mobile.cache.middleware.CacheFlavourMiddleware``
Adds ``X-Flavour`` header to ``request.META`` in ``process_request`` and
adds this header to ``response['Vary']`` in ``process_response``.
``django_mobile.cache.middleware.FetchFromCacheFlavourMiddleware``
Adds ``X-Flavour`` header to ``request.META`` in ``process_request``

``django_mobile.cache.middleware.UpdateCacheFlavourMiddleware``
Adds ``X-Flavour`` header to ``response['Vary']`` in ``process_response`` so that Django's ``CacheMiddleware`` know that it should take into account the content of this header when looking up the cached content on next request to this URL.


Customization
Expand Down
17 changes: 9 additions & 8 deletions django_mobile/cache/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
from functools import wraps
from django.views.decorators.cache import cache_page as _cache_page
from django.utils.decorators import decorator_from_middleware
from django_mobile.cache.middleware import CacheFlavourMiddleware

from django.views.decorators.cache import cache_page as _django_cache_page
from django.utils.decorators import decorator_from_middleware
from django_mobile.cache.middleware import FetchFromCacheFlavourMiddleware, UpdateCacheFlavourMiddleware

__all__ = ('cache_page', 'vary_on_flavour')
__all__ = ('cache_page', 'vary_on_flavour_fetch', 'vary_on_flavour_update')


vary_on_flavour = decorator_from_middleware(CacheFlavourMiddleware)
vary_on_flavour_fetch = decorator_from_middleware(FetchFromCacheFlavourMiddleware)
vary_on_flavour_update = decorator_from_middleware(UpdateCacheFlavourMiddleware)


def cache_page(*args, **kwargs):
'''
Same as django's ``cache_page`` decorator, but wraps the view into
``vary_on_flavour`` decorator before. Makes it possible to serve multiple
additional decorators before and after that. Makes it possible to serve multiple
flavours without getting into trouble with django's caching that doesn't
know about flavours.
'''
decorator = _cache_page(*args, **kwargs)
decorator = _django_cache_page(*args, **kwargs)
def flavoured_decorator(func):
return decorator(vary_on_flavour(func))
return vary_on_flavour_fetch(decorator(vary_on_flavour_update(func)))
return flavoured_decorator
15 changes: 14 additions & 1 deletion django_mobile/cache/middleware.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
from django_mobile import get_flavour, _set_request_header
import warnings

from django.utils.cache import patch_vary_headers
from django_mobile import get_flavour, _set_request_header


class CacheFlavourMiddleware(object):
def __init__(self):
warnings.warn('CacheFlavourMiddleware does nothing and should be abandoned.'
'The intended behavior cannot be implemented using one middleware.'
'Use separate FetchFromCacheFlavourMiddleware and UpdateCacheFlavourMiddleware instead.'
'Refer to https://github.com/gregmuellegger/django-mobile/pull/64 for details',
category=DeprecationWarning)


class FetchFromCacheFlavourMiddleware(object):
def process_request(self, request):
_set_request_header(request, get_flavour(request))


class UpdateCacheFlavourMiddleware(object):
def process_response(self, request, response):
patch_vary_headers(response, ['X-Flavour'])
return response