Search code examples
javascriptjsondjangohttp-status-code-400

BadRequest can't return JSON?


I am trying to return a JSON object along with a 400 error code. This correctly returns the object (e.g. {"email": ["A user with that email address already exists."]}:

return HttpResponse(json.dumps(dict(form.errors.items())))

Whereas these all just return an unreadable object ([object Object]):

return BadRequest(json.dumps(dict(form.errors.items())))
return HttpResponseBadRequest(json.dumps(dict(form.errors.items())))
return BadRequest(json.dumps(dict(form.errors.items())), content_type='application/json')

How do I get the readable object along with a 400 Bad Request error code?

Edit: as requested, here is the javascript (jQuery) code (edited for brevity):

// Account settings form is submitted
$(".form").on("submit", function(event) {
    event.preventDefault();
        
    // Post the form
    $.post("/edit_email/", $(this).serialize())
        .done(function(data) {
            if (data == "Email has been changed.") { // This check shouldn't be needed
                setTimeout(function() {
                    logout($("meta[name='csrf-token']").attr("content"), false);
                    window.location.href = "/";
                }, 1000);
            }
            else { // This should go in .fail
                $("#emailAlert").html($.parseJSON(data).email.join("<br/>")).removeClass("alert-hidden");
            }
        })
        .fail(function(data) {
            console.log(data); // Always returns [object Object]
        });
});

And my Django view:

def edit_email(request):
if not request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' or not request.method == "POST":
    return HttpResponseNotAllowed(["POST"])
        
if request.POST.get("email") == request.user.email:
    return HttpResponse(json.dumps( { "email": [ "Please enter a different email address." ] }))
else:
    form = EditEmailForm(request.POST, instance=request.user)

    if form.is_valid():
        form.save()
        return HttpResponse("Email has been changed.")
    else:
        return HttpResponse(json.dumps(dict(form.errors.items())))
        # return BadRequest(json.dumps(dict(form.errors.items())), content_type='application/json')

Solution

  • Probably the easiest way is a JsonResponse [Django-doc] with status=400:

    def my_view(request):
        # …
        return JsonResponse(dict(form.errors.items()), status=400)

    this also omits serializing manually.