import logging try: import json except ImportError: import simplejson as json log = logging.getLogger(__name__) class JSONResponse(object): """JSONResponse provides a standard method of responding to all JSON ajax requests. So that we can determine success/failure, related messages, and any html data payload we wish to send back to the client """ success = False message = "" payload = {} def __init__(self, success=False, message=None, payload=None): """Create JSONResponse Check for success, message, payload and make sure payload is a dict object """ if success: self.success = True if message is not None: self.message = str(message) else: self.message = "" if payload is not None and isinstance(payload, dict): self.payload = payload else: self.payload = {} def jsonify(self): """Return a json string of the response """ return json.dumps(self.dict_response()) def json_response(self, response): """Return a json response with headers set manually If we want to combine a single json/html response in one controller we can't use the jsonify decorator. We need to do the work that the jsonify decorator does in here """ response.headers['Content-Type'] = 'application/json' return self.jsonify() def dict_response(self): """Build a dictionary of the response object """ return {"success": self.success, "message": self.message, "payload": self.payload} from decorator import decorator def mijson(): """Action decorator that formats output for JSON Given a function that will return content, this decorator will turn the result into JSON, with a content-type of 'application/json' and output it. adds a method to the controller self.accepts_json() It checks if the request comes in accepting json and returns a JSONResponse object pulling from: self.json.success self.json.message self.json.payload returned html content is placed into json.payload.html Otherwise it just returns the html output returned. A template variable is set so that the template can conditionaly inherit or not c.request_ajax = Bool Sample Controller: @myjson() def pause(self, id): result = SomeObj.pause() if result: self.json.success = True self.json.message = 'Paused' else: self.json.success = False self.json.message = 'Failed' self.json.payload['job_id'] = id return '

Result was: %s

' % message Response: {'success': true, 'message': 'Paused', 'payload': {'html': '

Result was: Paused

'}} """ def wrapper(func, self, *args, **kwargs): request = self._py_object.request response = self._py_object.response def controller_accepts_json(): return 'application/json' in request.headers.get('accept', '') is_json = False self._py_object.c.request_ajax = False self.accepts_json = controller_accepts_json # go ahead and put this on the controller # but we'll only use it if this is a json request self.json = JSONResponse() self.json.success = False self.json.message = "" self.json.payload = {} if self.accepts_json(): is_json = True # let the template know it's an ajax request self._py_object.c.request_ajax = True html = func(self, *args, **kwargs) if is_json: response.headers['Content-Type'] = 'application/json' # grab the returned html content and place it in the payload under the # key html self.json.payload['html'] = html log.debug("Returning JSON wrapped action output") return self.json.jsonify() else: return html return func(self, *args, **kwargs) return decorator(wrapper)