99

I want to return status code 204 No Content from a Django view. It is in response to an automatic POST which updates a database and I just need to indicate the update was successful (without redirecting the client).

There are subclasses of HttpResponse to handle most other codes but not 204.

What is the simplest way to do this?

Braiam
  • 1
  • 11
  • 47
  • 78
Flash
  • 15,945
  • 13
  • 70
  • 98
  • I haven't done this before, but have you tried setting the status attribute of the response object before returning the response from your view? Also, here is another SO question about this: http://stackoverflow.com/questions/408541/how-to-produce-a-303-http-response-in-django – alan Sep 18 '12 at 12:03

4 Answers4

210
return HttpResponse(status=204)
Steve Mayne
  • 22,285
  • 4
  • 49
  • 49
  • 5
    Thanks. W3C states "The 204 response MUST NOT include a message-body" so (assuming the content parameter maps to the message body) it should be blank though, right? – Flash Sep 18 '12 at 14:58
  • 1
    For anyone reading who isn't just concerned with a 204 code you can use a message body with Django's HTTPResponse methods. – Braden Holt Dec 19 '17 at 19:46
  • More here https://docs.djangoproject.com/en/3.0/topics/http/views/#returning-errors – Josh Mar 31 '20 at 05:25
  • 1
    And instead of using magic numbers, django also provides constants (see https://www.django-rest-framework.org/api-guide/status-codes/), e.g. `return HttpResponse(status=rest_framework.status.HTTP_204_NO_CONTENT)` – nietonfir Mar 07 '22 at 12:42
28

When using render, there is a status keyword argument.

return render(request, 'template.html', status=204)

(Note that in the case of status 204 there shouldn't be a response body, but this method is useful for other status codes.)

Mark
  • 18,730
  • 7
  • 107
  • 130
  • Wouldn't this cause a redirect though? – GobSmack Jul 29 '15 at 16:12
  • No redirect needed, it should do the same as the top answer, just shorter syntax. (Using status code 204 for a redirect would be very weird, if it works at all). – Mark Jul 29 '15 at 20:47
  • Oh.. Is there a way I could pass an error status without actually reloading the page or redirecting to new page? I want to use it when a file that user is trying to save already exists. I tried 409 & 422. But, they redirect it to new page. I know AJAX is the other solution. But was wondering if Django had any trick. – GobSmack Jul 30 '15 at 00:14
  • 1
    Status codes are used when visitors are loading a page. So they have to be already loading a page; changing the code doesn't cause an extra redirect but you're still loading a new page. If they're on a page and you want to inform them without reloading, then I don't think there's a way to update the code of the current page (I don't think it would be terribly useful anyway). So: if they save a form which sends them to a new page, then you can choose any status code for the result page. If it doesn't load a new page, just show message and forget status code. – Mark Jul 30 '15 at 20:25
  • I get what you're saying. But, I really need to do just update the page. So, I guess, I'll have to use AJAX + Django :( Thanks a lot though! – GobSmack Jul 30 '15 at 20:33
  • Well ajax is a good way for that, but then you're just changing the ajax request status code, not the main page. – Mark Jul 31 '15 at 15:58
23

Either what Steve Mayne answered, or build your own by subclassing HttpResponse:

from django.http import HttpResponse

class HttpResponseNoContent(HttpResponse):
    status_code = 204

def my_view(request):
    return HttpResponseNoContent()
rantanplan
  • 7,283
  • 1
  • 24
  • 45
0

The other answers work mostly, but they do not produce a fully compliant HTTP 204 responses, because they still contain a content header. This can result in WSGI warnings and is picked up by test tools like Django Web Test.

Here is an improved class for a HTTP 204 response that is compliant. (based on this Django ticket):

from django.http import HttpResponse

class HttpResponseNoContent(HttpResponse):
    """Special HTTP response with no content, just headers.

    The content operations are ignored.
    """

    def __init__(self, content="", mimetype=None, status=None, content_type=None):
        super().__init__(status=204)

        if "content-type" in self._headers:
            del self._headers["content-type"]

    def _set_content(self, value):
        pass

    def _get_content(self, value):
        pass

def my_view(request):
    return HttpResponseNoContent()
Erik Kalkoken
  • 30,467
  • 8
  • 79
  • 114