João Pedro Francese  committed 697a1fb

* AjaxView now accepts alternative returns:
- (HTTP_status_code, context) to return a different HTTP status code with a specific context
- HTTP_status_code to return a different HTTP status code with no context

* JsonResponse now accepts an optional response_cls argument used to build the response instance.
* JsonErrorResponse removed.

  • Participants
  • Parent commits 5f7b769

Comments (0)

Files changed (2)

File inoa/http/

     status_code = 204
-def JsonResponse(data, cls=None):
+def JsonResponse(data, json_cls=None, response_cls=None):
     Returns an HttpResponse with JSON content type. Converts the data parameter to JSON automatically.
+    Accepts two optional parameters.
+    - json_cls: a subclass of simplejson.JSONEncoder
+    - response_cls: a subclass of django.http.HttpResponse
-    cls = cls or ExtendedJSONEncoder
-    return HttpResponse(simplejson.dumps(data, cls=cls), mimetype="application/json")
-def JsonErrorResponse(data, cls=None):
-    """
-    Returns an HttpResponseBadRequest with JSON content type. Converts the data parameter to JSON automatically.
-    Errors can be accessed parsing the 'responseText' attribute of the Http response.
-    """
-    cls = cls or ExtendedJSONEncoder
-    return HttpResponseBadRequest(simplejson.dumps(data, cls=cls), mimetype="application/json")
+    json_cls = json_cls or ExtendedJSONEncoder
+    response_cls = response_cls or HttpResponse
+    return response_cls(simplejson.dumps(data, cls=json_cls), mimetype="application/json")

File inoa/views/

 # -*- coding: utf-8 -*-
-from django.http import HttpResponseBadRequest
+from django.http import HttpResponseBadRequest, HttpResponse,\
+    HttpResponseNotFound, Http404
 from django.shortcuts import render
 from django.views.generic.base import View
 from functools import partial
     Returns the rendered HTML if the request.is_ajax() == False, otherwise returns a JsonResponse of the context.
     Define httpmethod_context(self, request) methods [e.g. get_context] that return a context object, which should be
-    dictionary-like objects that SimpleJson knows how to serialize.
+    dictionary-like objects that SimpleJson knows how to serialize, or None (which will be converted to an empty dictionary).
     Set a template_name attribute in your class with the template name for this view.
     If not set, non-ajax requests will return an HTTP error.
-    If you want to return a specific HttpResponse in your httpmethod_context() method,
+    You must also create two templates in your root template folder: '4xx.html' and '5xx.html',
+    which will be called when your view returns an error code in these ranges.
+    If you want to return an HTTP code other than 200 OK, return a 2-tuple (code, context) instead.
+    Code can be either an integer or a subclass of django.http.HttpResponse.
+    If you don't need to supply a context, you can simply return a subclass of HttpResponse. 
+    If you want to return a specific HttpResponse instance in your httpmethod_context() method,
     raise a ResponseWrapperException with your response wrapped in.
             return HttpResponseBadRequest
-            ctx = context_method(request, *args, **kwargs)
+            data = context_method(request, *args, **kwargs)
         except self.ResponseWrapperException as ex:
             return ex.response
+        except Http404 as ex:
+            data = HttpResponseNotFound
+        success_code = HttpResponse.status_code
+        if isinstance(data, HttpResponse) or (isinstance(data, type) and issubclass(data, HttpResponse)):
+            status_code = data.status_code
+            ctx = {}
+        elif (isinstance(data, tuple) or isinstance(data, list)) and len(data) == 2:
+            status_code = getattr(data[0], 'status_code', data[0])
+            ctx = data[1] or {}
+        else:
+            status_code = success_code
+            ctx = data or {}
         if request.is_ajax():
-            return JsonResponse(ctx)
+            response = JsonResponse(ctx)
+        elif status_code < 400:
+            response = render(request, self.template_name, ctx)
-            return render(request, self.template_name, ctx)
+            error_ctx = {'request_path': request.path, 'http_status_code': status_code}
+            error_ctx.update(ctx)
+            error_template = '4xx.html' if status_code < 500 else '5xx.html'
+            response = render(request, error_template, error_ctx)
+        response.status_code = status_code
+        return response