Created
August 15, 2012 03:43
-
-
Save pcostesi/3355525 to your computer and use it in GitHub Desktop.
Flask view decorator to dispatch a request into different handlers by mimetypes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@split | |
@login_required | |
def hello(): | |
return render_template('hello.html') | |
@hello.for_mimetype("application/json") | |
@login_required | |
def hello(): | |
return jsonify({"hello":"flask"}) | |
@hello.wrap | |
def hello(result): | |
logging.info("got a result %s", result) | |
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import update_wrapper | |
from flask import redirect, request, url_for | |
import types | |
class split(object): | |
DEFAULT_MIMETYPE = '*/*' | |
def __init__(self, view): | |
""" Default render view """ | |
default = type(self).DEFAULT_MIMETYPE | |
self.__dispatch_to = {default: view, None: view} | |
self.__targets = [default] | |
update_wrapper(self, view) | |
def for_mimetype(self, mimetype): | |
def deco(f): | |
self.__dispatch_to[mimetype] = f | |
self.__targets = [mimetype] + self.__targets | |
return self | |
return deco | |
def wrap(self, func): | |
self._wrap = func | |
return self | |
def __get__(self, obj, type=None): | |
if obj is None: | |
return self | |
# Let `func' be the method we're decorating. Return | |
# `self' bound to `obj', so it gets called as func(obj, ...) | |
# The bound method does something like this: | |
# def f(*args, **kwargs): | |
# return self(obj, *args, **kwargs) | |
# using functools.partial(self, obj) also does the trick. | |
# If we weren't wrapping this method, then it would be called | |
# by the wrapping class as an object and NOT as a method, so it | |
# would omit the `obj' argument. | |
# Returning a function or a partial works because Python would | |
# wrap them as bound methods. | |
# Yeah, it's a mess. | |
return types.MethodType(self, obj, type) | |
def __call__(self, *args, **kwargs): | |
best_match = request.accept_mimetypes.best_match(self.__targets) | |
target = self.__dispatch_to[best_match] | |
if not target: | |
return redirect(url_for("404.html")), 404 | |
result = target(*args, **kwargs) | |
if getattr(self, "_wrap", None) and callable(self._wrap): | |
return self._wrap(*args, **kwargs) | |
return result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment