Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best way to decorate a view function #318

Open
mmautner opened this issue May 30, 2014 · 5 comments
Open

Best way to decorate a view function #318

mmautner opened this issue May 30, 2014 · 5 comments

Comments

@mmautner
Copy link

I was investigating issue #99 about how to cache API results and realized that the Flask-Restless pre-/post-processors are not the way to go as they cannot return a response in lieu of what the class-based view functions return.

What is the best way to then go about decorating the views that get added to the app object by the Flask-Restless blueprint?

Here's a go I had it, but am curious whether there's a better/more harmonious way to do it:

#!/usr/bin/env python

import hashlib
from functools import update_wrapper
from flask import Flask
from flask import request
import flask.ext.sqlalchemy
import flask.ext.restless
from werkzeug.contrib.cache import MemcachedCache
cache = MemcachedCache(['127.0.0.1:11211'])

def get_cache(func):
    def wrapper(*args, **kwargs):
        # < 250 chars for memcached
        cache_key = hashlib.md5(request.full_path).hexdigest()
        if request.method == 'GET' and cache.get(cache_key):
            return cache.get(cache_key)

        result = func(*args, **kwargs)

        if request.method == 'GET':
            cache.set(cache_key, result)
        return result
    return update_wrapper(wrapper, func)

db = flask.ext.sqlalchemy.SQLAlchemy()

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode, unique=True)
    birth_date = db.Column(db.Date)

class Person2(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode, unique=True)
    birth_date = db.Column(db.Date)

def create_app():
    app = Flask(__name__)
    app.config['DEBUG'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
    db.init_app(app)

    db.drop_all(app=app)
    db.create_all(app=app)

    manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
    manager.create_api(Person, methods=['GET', 'POST', 'DELETE'])
    manager.create_api(Person2, methods=['GET', 'POST', 'DELETE'])

    # hackish view decoration:
    for model in [Person, Person2]:
        model_route = '{0}api0.{0}api'.format(model.__name__.lower())
        app.view_functions[model_route] = get_cache(app.view_functions[model_route])

    return app

if __name__ == "__main__":
    create_app().run(debug=True)
@jfinkels
Copy link
Owner

Would it help to allow the user to add decorator functions to the view methods (by extending the list stored at views.API.decorators)? Those decorators are applied at each request.

@chfw
Copy link

chfw commented Aug 28, 2014

Why would a server need caching for the responses of PUT, POST and DELETE? Caching of GET response is my concern.

@jfinkels
Copy link
Owner

According to StackOverflow, if the HTTP POST request includes the appropriate headers, then the application running on the server may cache an HTTP response, whatever that may mean. I think it should be theoretically allowed even if not used often in practice. Plus it may be easier to allow a decorator on top of all methods, rather than on just one.

Perhaps Flask-Restless should provide some default caching, checking for the appropriate HTTP headers?

@chfw
Copy link

chfw commented Aug 29, 2014

Given that I could select which HTTP method to do caching, I would support your idea of one decorator for four methods.

Internet Explorer had default caching, which took me some time to figure it out. So, personally I wouldn't want default caching unless I would like to have it.

In the example, I didn't see cache duration and cache storage. Hopefully, it's possible to use Flask-Cache.

@reubano
Copy link
Contributor

reubano commented Jun 9, 2021

...
model_route = '{0}api0.{0}api'.format(manager.collection_name(model))
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants