2012-02-23 17 views
16

Rozszerzenie pojemnika na kolbę ma dekorator @cache.memoize do buforowania widoku zawierającego widoki *args i **kwargs. Jednak niektóre z moich widoków również zawierają ciąg zapytania o adres URL, na przykład /foo/image?width=640. Dekorator dodaje do funkcji dekorowanej widoku metodę make_cache_key, której można użyć do dostosowania klucza pamięci podręcznej. Nie wiem jednak, jak uzyskać request.args poza kontekstem normalnego żądania.Parametry ciągu znaków zapytania z kolbą w pamięci podręcznej również

Pomysły na to, jak sprawić, aby funkcja @cache.memoize działała również z ciągami zapytań adresów URL?

+2

Można wyodrębnić funkcję generowania obrazu z widoku i cache to wyniki. – reclosedev

+0

Tak, to załatwiło sprawę. – Adrian

+1

To jest absurdalnie frustrująca odpowiedź, ponieważ pojawia się w wyszukiwaniu za pomocą skrzynki podręcznej i jak zarządzać trasami z parametrami url, ale nie zapewnia rzeczywistej odpowiedzi. – blueblank

Odpowiedz

27

Miałem ten sam problem dzisiaj i nie znalazłem żadnego przykładu w Internecie, więc trochę się rozegrałem.

To mój 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') 

Można użyć request.url zamiast ścieżki i mieszany args. Potrzebowałem również dodać język użytkowników do klucza.

Buforowanie widok:

@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 

to działa, ale myślę, że to trochę kłopotliwe. Okazało się, że key_prefix może być wywoływalny, który generuje cały klucz cache_key. Dlatego też możemy to zrobić:

@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 

właśnie wymyślił to i nie stosować go w produkcji jeszcze - więc może nie działać we wszystkich przypadkach.

+7

Dzięki! To zadziałało dla mnie: 'def make_cache_key (* args, ** kwargs): return request.url' – reubano

+0

Może to doprowadzić do nagromadzenia duplikatów danych w redis, czyż nie? Jeśli poprosisz o powiedzenie, '/ comments? Blah = blah' i'/comments? Foo = foo', oba te wyniki dają takie same wyniki, ponieważ na przykład argumenty są ignorowane, odpowiedzi będą buforowane. – reptilicus

+0

@reptilicus To jest poprawny punkt! Ale może nie przedstawiać praktycznego problemu dla typowych użytkowników (niekoniecznie mucking z adresami URL). W każdym przypadku można byłoby zrobić podobnie dynamiczną metodę, z większą spójnością: 'def make_cache_key (* args, ** kwargs): return (request.path,) + (arg dla arg w args) + (wpis dla wpisu w posortowaniu (kwargs.items())) '(untested, tylko punkt początkowy) – hangtwenty

4

Od wersji 0.3.4, można key_prefix być wymagalne:

Nowości w wersji 0.3.4: Może być ewentualnie wywoływalnym który nie wymaga żadnych argumentów, ale zwraca ciąg znaków, który będzie używany jako cache_key.

Oto doc: Flask-Cache

+0

memoize() nie akceptuje parametru key_prefix. –

3

dzięki SMOE i Asdine El Hrychy, oto moja wersja; generuje klucz dla bieżącego ciągu zapytania URL + (który, moim zdaniem, musi być powszechną potrzebą).

Uwaga:

  • ciąg kwerendy są sortowane, starając się pozostać taka sama, jeśli poprosisz ?a=foo&b=bar lub ?b=bar&a=foo (początkowo zrobiłem (k, v) for k, val in flask.request.args.viewitems() for v in sorted(val) ale zmieniłem aby posortować too klucze)
  • obsługuje sam klucz z wieloma zdarzeniami, tzn: ?a=foo&a=bar (i wróci ten sam klucz jak ?a=bar&a=foo)
  • key_prefix argumentem jest tylko dla cached a nie dla memoize, przynajmniej Kolba-cache 0,13.1, a ponieważ zajmuje ścieżkę URL, powinien on pasować do większości memoize przypadków użycia

Kod:

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

ponieważ nie chcę brata się zrobić więcej, działają jak środki args , ale następujący kod może pracować i może spełnić moje wymagania:

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

można użyć flask-caching:

Kontynuacja Extension Kolba-Cache

z którym można zrobić coś takiego:

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

Dokumenty z 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

Po prostu przegrałem oba komentarze w GithHub i tę odpowiedź;) –

Powiązane problemy