2012-02-23 23 views
16

La extensión de matraz-caché tiene un decorador @cache.memoize para almacenar en caché una vista que incluye la vista *args y **kwargs. Sin embargo, algunas de mis vistas también toman una cadena de consulta URL, por ejemplo /foo/image?width=640. El decorador agrega un método make_cache_key a la función de vista decorada que se puede usar para personalizar la clave de cachématraz-caché memoize parámetros de cadena de consulta URL también

Sin embargo, no sé cómo obtener el request.args fuera del contexto de solicitud normal.

¿Alguna idea de cómo hacer que el @cache.memoize trabaje con cadenas de consulta de URL también?

+2

Usted puede extraer función de generación de imágenes de la vista y caché sus resultados. – reclosedev

+0

Sí, eso funcionó. – Adrian

+1

Esta es una respuesta ridículamente frustrante, ya que aparece en una búsqueda para usar el matraz-caché y cómo administrar rutas con parámetros de URL, pero no proporciona una respuesta real. – blueblank

Respuesta

27

Tuve el mismo problema hoy y no encontré ningún ejemplo en Internet, así que jugué un poco.

Esta es mi make_cache_key:

def make_cache_key(*args, **kwargs): 
    path = request.path 
    args = str(hash(frozenset(request.args.items()))) 
    lang = get_locale() 
    return (path + args + lang).encode('utf-8') 

Usted podría utilizar request.url en lugar de ruta y los argumentos hash. Necesitaba agregar el lenguaje de los usuarios a la clave también.

Almacenamiento en caché de una vista:

@app.route("/test") 
@cache.cached(timeout=50) 
def test(): 
    a = request.args.get('a') 
    b = request.args.get('b') 
    return a + b 
test.make_cache_key = make_cache_key 

Funciona, pero creo que es algo engorroso. Resultó que el keyprefix puede ser invocable y genera toda la clave cache_key. Por lo tanto podemos hacer esto:

@app.route("/test2") 
@cache.cached(timeout=50, key_prefix=make_cache_key) 
def test2(): 
    a = request.args.get('a') 
    b = request.args.get('b') 
    return a + b 

yo acabamos con esto y no lo han utilizado en la producción todavía - por lo que pueden no funcionar en todos los casos.

+7

Gracias! Esto funcionó para mí: 'def make_cache_key (* args, ** kwargs): return request.url' – reubano

+0

Esto podría llevar a una cierta acumulación de datos duplicados en redis, ¿no es así? Si solicita decir '/ comments? Blah = blah', y'/comments? Foo = foo', los cuales producen los mismos resultados porque, por ejemplo, los argumentos se ignoran, las respuestas se almacenarán en caché. – reptilicus

+0

@reptilicus ¡Este es un punto válido! Pero puede no ser un problema práctico para los usuarios típicos (no necesariamente están eliminando las URL). En cualquier caso, se podría hacer una forma similarmente dinámica, con una consistencia más fuerte: 'def make_cache_key (* args, ** kwargs): return (request.path,) + (arg for arg in args) + (entrada para entrada en ordenada (kwargs.items())) '(no probado, solo un punto de partida) – hangtwenty

4

Desde la versión 0.3.4, puede haber un key_prefix exigible:

Nuevo en la versión 0.3.4: Se puede opcionalmente ser un exigible, que no tiene argumentos, pero devuelve una cadena que se utiliza como el cache_key.

Aquí es el doc: Flask-Cache

+0

memoize() no acepta el parámetro key_prefix. –

3

gracias a SMOE y Asdine El Hrychy, aquí está mi versión; genera una clave para la cadena de consulta + URL actual (que, en mi opinión, debe ser una necesidad común).

Nota:

  • la cadena de consulta se ordena en un intento de mantenerse el mismo si solicita ?a=foo&b=bar o ?b=bar&a=foo (inicialmente lo hice (k, v) for k, val in flask.request.args.viewitems() for v in sorted(val) pero cambió para ordenar las claves también)
  • Soporta misma clave con múltiples ocurrencias, es decir: ?a=foo&a=bar (y devolverá la misma tecla que ?a=bar&a=foo)
  • key_prefix argumento es sólo para cached y no para memoize, al menos como de matraz de Cache 0,13.1, y ya que toma la ruta URL, debe caber la mayoría de los casos de uso memoize

El código:

import flask 
import urllib 

def cache_key(): 
    args = flask.request.args 
    key = flask.request.path + '?' + urllib.urlencode([ 
     (k, v) for k in sorted(args) for v in sorted(args.getlist(k)) 
    ]) 
    return key 

# ... 
import time 

@app.route('/test') 
@cache.cached(timeout=600, key_prefix=cache_key) 
def test(): 
    return time.time() 

@app.route('/<value>/test') 
@cache.cached(timeout=3600, key_prefix=cache_key) 
def value_test(value): 
    return flask.jsonify(time=time.time(), value=value) 
0

ya no quiero hermano a mí mismo para hacer más trabajo al igual que cita los argumentos , pero el siguiente código puede trabajar y puede satisfacer mi requisito:

from flask import request 

def cache_key(): 
    return request.url 

@main.route("/test/", methods=['GET']) 
@cache.cached(timeout=10, key_prefix=cache_key) 
def do_somthing(): 
    return "hello %s" % str(request.args) 
2

Usted puede utilizar flask-caching:

Continuación del matraz de caché Extensión

con el que puede hacer algo como esto:

@app.route("/") 
@cache.cached(timeout=10, query_string=True) 
def index(): 
    return render_template('index.html') 

Docs desde source code:

:param query_string: Default False. When True, the cache key 
        used will be the result of hashing the 
        ordered query string parameters. This 
        avoids creating different caches for 
        the same query just because the parameters 
        were passed in a different order. See 
        _make_cache_key_query_string() for more 
        details. 
+1

Acabo de votar tanto tu comentario en GithHub como esta respuesta;) –

Cuestiones relacionadas