Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Sample code to implement multiple views/handlers depending on the Accept and Content-Type headers.
from contextlib import contextmanager
import cherrypy
from cherrypy.lib import cptools
class View(object):
__mime__ = 'text/html'
def __init__(self, controller):
self.ctrl = controller
class Controller(object):
__views__ = ()
def __init__(self):
self.__branches__ = {}
def __setattr__(self, name, value):
# if is a controller, merge the subtree.
if isinstance(value, Controller):
for mime, branch in value.__branches__.items():
if mime not in self.__branches__:
self.__create_branch(mime) # bridge branch.
setattr(self.__branches__[mime], name, branch)
super(Controller, self).__setattr__(name, value)
def __init_branches(self):
for ViewClass in self.__views__:
(self, ), # connect the controller.
# create the routes of the subcontrollers already binded to the class
# We are using again the "isinstance" because the value could
# be a method and this will make it a function.
for name, value in vars(self.__class__).items():
if not name.startswith('_') and \
isinstance(value, Controller):
setattr(self, name, value)
def __create_branch(self, mime, initargs=(), *parents):
if mime in self.__branches__:
raise Exception('Branch "%s" already exists' % mime)
clsname = ''.join([self.__class__.__name__,
Branch = type(clsname, parents, {})
self.__branches__[mime] = Branch(*initargs)
class ContentTypeDispatcher(cherrypy.dispatch.Dispatcher):
def _branch(self, root, branch_name):
app =
branch = root.__branches__[branch_name]
app.root = branch
app.root = root
def find_handler(self, path_info):
app =
parentcls = super(ContentTypeDispatcher, self)
bmimes = list(app.root.__branches__)
if bmimes:
if 'text/html' in bmimes: # set text html at top.
bmimes.insert(0, bmimes.pop(bmimes.index('text/html')))
branch_name = cptools.accept(media=bmimes)
with self._branch(app.root, branch_name):
return parentcls.find_handler(path_info)
except AttributeError as err:
return parentcls.find_handler(path_info)
# Example
class JSONComment(View):
__mime__ = 'application/json'
def index(self):
return {'cnt': "Comment index",
'ctrl': str(self.ctrl.fetch_comment())}
class JSONPost(View):
__mime__ = 'application/json'
def index(self):
return {'cnt': "Post index",
'ctrl': str(self.ctrl)}
class HTMLPost(View):
def index(self):
return "HTML Post INDEX"
class HTMLRoot(View):
def index(self):
return "HTML root index"
class Comment(Controller):
__views__ = [JSONComment]
def fetch_comment(self):
return {"name": "Example",
"content": "Le content"}
class Post(Controller):
__views__ = [HTMLPost, JSONPost]
class Root(Controller):
__views__ = [HTMLRoot]
post = Post()
if __name__ == '__main__':
root = Root() = Comment()
config = {'/': {'request.dispatch': ContentTypeDispatcher()}}
cherrypy.quickstart(root, config=config)

This comment has been minimized.

Copy link
Owner Author

cyraxjoe commented Dec 22, 2012

To test:

 curl -v  -H "Accept: application/json" -H "Content-type: application/json" localhost:8080/post/
 curl -v  -H "Accept: application/json" -H "Content-type: application/json" localhost:8080/post/comment/
 curl localhost:8080/post/
 curl localhost:8080/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.