Why Bother?
In looking at both Turbogears and Pylons, one of the way, way cool things that Turbogears had that Pylons didn't compare on is the ability to slap a decorator on a function and make it jsonify on demand (dependent on the url invocation).
Pylons claims to have something similar but is is not nearly as cool. Pylons seems to expect a different method. Yes, I know you can have two and one calls the other and then this and then that and stand on one foot while you code...
It doesn't have to be that way. I prefer Pylons for a number of reasons so here's how to make Pylons jsonify act like the Turbogears json, one method where you gather all the "return" data into a dict (or a "c" variable) and return it rendered (genshi is my poison of choice) or raw (as json).
The Turbogears way
@expose(template="my.html.template") @expose("json") def resource(self, arg): d1 = someFun(arg) return {'var1': dl}
The json decorator here checks the request query string for a key to go into json mode. The key is ..url..?tg_format=json. The great thing about Turbogears here is that the controller methods all return a dict. That makes it pretty easy for the wrapper function to just take the same output (a dict) and return it as json.
The Pylons way
Pylons now
Right now we can't pull off the same thing in pylons. The reason is that the return from a controller method is a call to render_response.
def resource(self, arg): c.d1 = someFun(arg) render_response("my_template")
You can't really throw a decorator on this because render_response will call render which runs the templating code. None of which you want if it's supposed to return json.
So right now you have to write a different class method just for your possible json call.
That Stinks!!! This will not be allowed to stand'''
How it Could be
I think... c._current_obj().dict gives us what we would have had in the Turbogears call, a dict of terms that are passed to the template.
That leaves us with the render_response problem. It's not too bad actually. render_response is imported from the myPackage.lib.base. In that package:
## in mypackage/lib/base.py ## change #from pylons.templating import render, render_response ## to from pylons.templating import render from pylons.templating import render_response as pylons_render_response from paste.request import parse_querystring #################################################### ## Then ADD the following function (not tested yet...much) def render_response(*args,**kwargs): # if json was not requested with `?format=json` call the 'normal' function if kwargs.get('json') is not 'OK' \ or ('format','json') not in parse_querystring(request.environ): pylons_render_response(*args,**kwargs) json_response =jsonify(lambda c:c._current_obj().__dict__) return json_response(c)
Now you don't even need a decorator for json responses. Only a ...?format=json at the end of the http request string.
That might be too much json. I suppose the modified render_response should check kwargs for a json='OK'. That way the programmer could allow json exactly where it is allowed.
Should it be the default? I suppose you could decide and even put it in the global config somewhere.
For now all that is needed is to end your method call with an additional keyword like:
return render_response('titles', json='OK')
Now the method can be called and it will render with thatever the titles template renders to but if the url query string inlucdes format=json the jsonify of the c global is called. One method no code changes beyond the keyword addition.
Also, in pylons, since we can decide during the method invocation which template to call (which we cannot in Turbogears) we can choose which returns can be allowed to jsonify.
