flask-cache icon indicating copy to clipboard operation
flask-cache copied to clipboard

Include query string parameters in cache key

Open makmanalp opened this issue 10 years ago • 12 comments

A really common use case for caching is that the result of an API call will change depending on query string parameters given.

Right now query parameters are being ignored: https://github.com/thadeusb/flask-cache/blob/master/flask_cache/init.py#L308

I hack around this by adding stuff to key_prefix, but it seems like this might be desirable as a default - I can't think of a situation where you'd add a query parameter to a URL and expect a different result.

A counterargument is that some things randomly add query parameters to URLs, like google analytics (utm_source etc), which will cause double caching. So we could solve that by either creating a blacklist (where we may miss things, but is simpler from a developer point of view) or by creating a whitelist (where it's probably more correct, as long as the developer remembers to add the GET params they use).

Is there any interest in this? I can take a shot at implementing it.

makmanalp avatar Dec 09 '14 20:12 makmanalp

+1 also if user is loged or not

rturk avatar Dec 09 '14 22:12 rturk

yes - should check for flask-login or you can pass a user class...

Very simple to add I would think?

aphillipo avatar Dec 19 '14 13:12 aphillipo

+1 needed this right now!

acasimiro avatar May 28 '15 18:05 acasimiro

defeinitely interested! Flask-Login and get parameters support would be great

kelvin22 avatar May 31 '15 16:05 kelvin22

With recent versions of Flask-cache, you can simulate it like this:

def make_key ():
  """Make a key that includes GET parameters."""
  return request.full_path

@app.route('/hello')
@cache.cached(key_prefix=make_key)
def view_hello():
    return "Hello, " + request.args.get('name')

Put anything you want in make_key().

davidmegginson avatar Aug 01 '15 13:08 davidmegginson

Sorry - I see that @makmanalp already mentioned key_prefix in the original issue. I do agree that full_path would be a better default, but in my app, I'll probably always need a custom key_prefix anyway.

davidmegginson avatar Aug 01 '15 13:08 davidmegginson

Hi,

Is this a good idea : ?

import hashlib
from flask import request

def func_cache_with_args(func_name, **kwargs):
    """Return hash value from func name and request.full_path

    Ex:  my_view + /api/v1/sdmx/INSEE/data/IPCH-2015-FR-COICOP/A.07120.?startPeriod=2011
    """
    return hashlib.sha256(func_name.encode("utf-8") + request.full_path.encode("utf-8")).hexdigest()

@cache.memoize(360, make_name=func_cache_with_args)
def my_view(flowRef, key=None, providerRef=None, version="all"):
   ...

srault95 avatar Feb 21 '16 16:02 srault95

@srault95 Well, I think this may be a bit of a tangent to the original ticket. I don't see anything wrong with that, but there's a tradeoff in hashing cache keys. You're obscuring what the keys mean, and thus maybe getting rid of the capability to nuke only part of the cache by filtering through existing keys based on some rule (e.g. only the v2 api keys) - short of some other mechanism that either can enumerate all cached things or stores categories of keys elsewhere.

makmanalp avatar Feb 21 '16 22:02 makmanalp

A little addition/modification to @davidmegginson's contribution:

def make_key_prefix():
  """Make a key that includes GET parameters."""
  return url_for(request.endpoint, **request.args)

url_for seems to order request.args in the resultant URL, preventing double caching of urls with shuffled querystring params/args.

And for view functions with view_args:

def make_key_prefix():
  """Make a key that includes GET parameters and view/route args."""
    args = {**request.view_args, **request.args}
    return url_for(request.endpoint, **args) 

kerdany avatar Aug 19 '16 17:08 kerdany

Just cutting the path for this discussion, it is already 'natively' implemented on Flask, through method memoize().

As described in documentation, cache.memoize() considers the function parameters, on the contrary of cache.cached().

frmaia avatar Dec 11 '16 13:12 frmaia

I think it's implemented in https://github.com/sh4nks/flask-caching/pull/35

eyalev avatar Nov 08 '17 13:11 eyalev

just wanted to confirm that using query_string=True as @eyalev said works.

ivica-k avatar Dec 28 '19 14:12 ivica-k