Ticket #4992: cache_by_request_full_path_v2.diff

File cache_by_request_full_path_v2.diff, 7.0 KB (added by guettli, 5 years ago)

Updated patch of PeterKz to apply cleanly to trunk. Added tests

  • docs/topics/cache.txt

     
    731731said to "vary on language."
    732732
    733733By default, Django's cache system creates its cache keys using the requested
    734 path (e.g., ``"/stories/2005/jun/23/bank_robbed/"``). This means every request
    735 to that URL will use the same cached version, regardless of user-agent
     734path and query -- e.g., ``"/stories/2005/?order_by=author"``. This means every
     735request to that URL will use the same cached version, regardless of user-agent
    736736differences such as cookies or language preferences. However, if this page
    737737produces different content based on some difference in request headers -- such
    738738as a cookie, or a language, or a user-agent -- you'll need to use the ``Vary``
  • django/utils/cache.py

     
    150150        value = request.META.get(header, None)
    151151        if value is not None:
    152152            ctx.update(value)
    153     path = md5_constructor(iri_to_uri(request.path))
     153    path = md5_constructor(iri_to_uri(request.get_full_path()))
    154154    cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % (
    155155        key_prefix, path.hexdigest(), ctx.hexdigest())
    156156    return _i18n_cache_key_suffix(request, cache_key)
    157157
    158158def _generate_cache_header_key(key_prefix, request):
    159159    """Returns a cache key for the header cache."""
    160     path = md5_constructor(iri_to_uri(request.path))
     160    path = md5_constructor(iri_to_uri(request.get_full_path()))
    161161    cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
    162162        key_prefix, path.hexdigest())
    163163    return _i18n_cache_key_suffix(request, cache_key)
    164164
    165165def get_cache_key(request, key_prefix=None):
    166166    """
    167     Returns a cache key based on the request path. It can be used in the
     167    Returns a cache key based on the request path and query. It can be used in the
    168168    request phase because it pulls the list of headers to take into account
    169169    from the global path registry and uses those to build a cache key to check
    170170    against.
     
    206206        return _generate_cache_key(request, headerlist, key_prefix)
    207207    else:
    208208        # if there is no Vary header, we still need a cache key
    209         # for the request.path
     209        # for the request.get_full_path()
    210210        cache.set(cache_key, [], cache_timeout)
    211211        return _generate_cache_key(request, [], key_prefix)
    212212
  • django/middleware/cache.py

     
    2323
    2424More details about how the caching works:
    2525
    26 * Only parameter-less GET or HEAD-requests with status code 200 are cached.
     26* Only GET or HEAD-requests with status code 200 are cached.
    2727
    2828* The number of seconds each page is stored for is set by the "max-age" section
    2929  of the response's "Cache-Control" header, falling back to the
     
    115115        if self.cache_anonymous_only:
    116116            assert hasattr(request, 'user'), "The Django cache middleware with CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True requires authentication middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware' before the CacheMiddleware."
    117117
    118         if not request.method in ('GET', 'HEAD') or request.GET:
     118        if not request.method in ('GET', 'HEAD'):
    119119            request._cache_update_cache = False
    120120            return None # Don't bother checking the cache.
    121121
  • django/http/__init__.py

     
    6161        return host
    6262
    6363    def get_full_path(self):
    64         return ''
     64        # RFC 3986 requires query string arguments to be in the ASCII range.
     65        # Rather than crash if this doesn't happen, we encode defensively.
     66        # taken from django/core/handlers/wsgi.py
     67        return '%s%s' % (self.path, self.META.get('QUERY_STRING', '') and ('?' + iri_to_uri(self.META.get('QUERY_STRING', ''))) or '')
    6568
    6669    def build_absolute_uri(self, location=None):
    6770        """
  • tests/regressiontests/cache/tests.py

     
    1414from django.core import management
    1515from django.core.cache import get_cache
    1616from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning
    17 from django.http import HttpResponse, HttpRequest
     17from django.http import HttpResponse, HttpRequest, QueryDict
    1818from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
    1919from django.utils import translation
    2020from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
     
    588588        request.path = request.path_info = self.path
    589589        return request
    590590
    591     def _get_request_cache(self):
     591    def _get_request_cache(self, query_string=None):
    592592        request = HttpRequest()
    593593        request.META = {
    594594            'SERVER_NAME': 'testserver',
    595595            'SERVER_PORT': 80,
    596596        }
     597        if query_string:
     598            request.META['QUERY_STRING']=query_string
     599            request.GET=QueryDict(query_string)
    597600        request.path = request.path_info = self.path
    598601        request._cache_update_cache = True
    599602        request.method = 'GET'
     
    629632        settings.CACHE_MIDDLEWARE_KEY_PREFIX="test"
    630633        settings.CACHE_BACKEND='locmem:///'
    631634        settings.USE_I18N = True
     635
     636        # cache with non empty request.GET
     637        request = self._get_request_cache(query_string='foo=bar&other=true')
     638        get_cache_data = FetchFromCacheMiddleware().process_request(request)
     639        # first access, cache must return None
     640        self.assertEqual(get_cache_data, None)
     641        response = HttpResponse()
     642        content='Check for cache with QUERY_STRING'
     643        response.content=content
     644        UpdateCacheMiddleware().process_response(request, response)
     645        get_cache_data = FetchFromCacheMiddleware().process_request(request)
     646        # cache must return content
     647        self.assertNotEqual(get_cache_data, None) # request with QUERY_STRING not cached.
     648        self.assertEqual(get_cache_data.content, content)
     649        request = self._get_request_cache(query_string='foo=bar&somethingelse=true')
     650        get_cache_data = FetchFromCacheMiddleware().process_request(request)
     651        # different QUERY_STRING, cache must be empty
     652        self.assertEqual(get_cache_data, None)
     653
     654        # i18n tests
    632655        en_message ="Hello world!"
    633656        es_message ="Hola mundo!"
    634 
    635657        request = self._get_request_cache()
    636658        set_cache(request, 'en', en_message)
    637659        get_cache_data = FetchFromCacheMiddleware().process_request(request)
Back to Top