2

I have created a view in my Django app that requires authentication to load. If the credentials are incorrect, then an error 403 page is sent back. Since I declared the view to be cached in the urls.py file, like this...

    url(r'^example/example-url/(?P<special_id>\d+)/$',
        cache_page(60 * 60 * 24 * 29, cache='site_cache')(views.example_view),
        name="example"),

... then even the error pages are being cached. Since the cache is for 29 days, I can't have this happen. Furthermore, if a the page is successfully cached, it skips the authentication steps I take in my view, leaving the data vulnerable. I only want django to cache the page when the result is a success, not when an error is thrown. Also, the cached page should only be presented after authentication in the view. How can I do this?

My cache settings in setting.py:

CACHES = {
'default': {
    'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    'LOCATION': 'unique-snowflake',
},
'site_cache': {
    'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
    'LOCATION': '/var/tmp/django_cache',
}

}

Thanks in advance

turtlefranklin
  • 509
  • 6
  • 14
  • Caching views is totally not worth it. – e4c5 Jun 27 '16 at 01:45
  • Unfortunately the view needs to be cached in order to reduce the load on the server. The view generated is a large, data-heavy feed that takes about 20 seconds to load while still being heavily optimized. Once it's created though, it's good for a month. So for this instance it is VERY worth it – turtlefranklin Jun 27 '16 at 01:51
  • 1
    Oh, Ok. I thought this was just another one of those premature optimization questions that we get all the time here. – e4c5 Jun 27 '16 at 01:53
  • 1
    But what are the errors you are talking about here? Internal errors? 404s? invalid data? While you are updating your question please also add your cache settings. – e4c5 Jun 27 '16 at 01:54
  • I throw an error 403 "Forbidden access" page, since the presentation of the view requires credentials. So that page is returned from the request. I'll add the cache settings – turtlefranklin Jun 27 '16 at 01:56
  • 1
    I think this is a bug with django cache per-view https://github.com/django/django/blob/1.9.7/django/middleware/cache.py#L78 it shouldn't cache responses that aren't 200 status – A. J. Parr Jun 27 '16 at 02:05
  • Why not just cache the result, instead of the entire view? – trinchet Jun 27 '16 at 02:06
  • ARJMP. Thanks for the suggestion. I did have an issue where the view I was responding with wasn't correctly returning a 403 status code. So I've since corrected it and the problem is half resolved, and the error page is no longer cached. But the data page is cached before testing authentication - not good. But I don't think it was a bug – turtlefranklin Jun 27 '16 at 02:17

1 Answers1

3

Simple work around. Change your urls.py like this.

url(r'^example/example-url/(?P<special_id>\d+)/$',
        views.example_view,
        name="example"),

Then modify your example_view like this:

def example_view(request, sepcial_id):
    if request.user.is_authenticated():
        key = 'exmpv{0}'.format(special_id)

        resp = cache.get(key)
        if not resp:
             # your complicated queries

             resp = render('yourtemplate',your context)
             cache.set(key, resp)
        return resp
     else:
         # handle unauthorized situations

Can I also interest you in switching to memcached instead of file based caching?

e4c5
  • 52,766
  • 11
  • 101
  • 134
  • I like the look of this! I'll try it out tomorrow morning and I'll award you the accepted answer if it works out. This seems like a brilliant way of handling caches. I'll look into memcached too – turtlefranklin Jun 27 '16 at 02:19
  • For this use-case. I think I'll stick with file-based caching, since I only expect the data to be read 1 to 4 times a month (by a bot). But thanks for the suggestion. Now I know the benefits of memcached! – turtlefranklin Jun 27 '16 at 02:27