Last Updated: February 25, 2016
·
15.76K
· lucasroesler

POSTing from Angular to Django

If you are using Django and AngularJS then you have probably run into the issue of trying to POST data to Djan go. For example,

$http({
    url: "<myawesomeview>",
    method: 'POST',
    data: { 'text': 'this is really important', 'date': '2014-06-09'}
})

The issue that arises is that AngularJS defaults to sending JSON data in the response body instead of urlencoded data, which is the type of data that Django is looking for. As a result, back in Django if we did the following

def myawesomeview(request):
    print request.POST
    print request.body

We would get

<QueryDict: {}>
u"{ 'text': 'this is really important', 'date': '2014-06-09'}"

back out on our console. If you have been using Django for even a little bit, then you realize that we were really expecting

<QueryDict: {u'text': u'this is really important', u'date': u'2014-06-09'}>
u"{ 'text': 'this is really important', 'date': '2014-06-09'}"

You can find my solution to this in this gist, which is kindly provided below:

UPDATE I found a bug in my previous version, I have updated it to address this, the primary issue was how list value were being handled.

class JSONMiddleware(object):
    """
    Process application/json requests data from GET and POST requests.
    """
    def process_request(self, request):
        if 'application/json' in request.META['CONTENT_TYPE']:
            # load the json data
            data = json.loads(request.body)
            # for consistency sake, we want to return
            # a Django QueryDict and not a plain Dict.
            # The primary difference is that the QueryDict stores
            # every value in a list and is, by default, immutable.
            # The primary issue is making sure that list values are
            # properly inserted into the QueryDict.  If we simply
            # do a q_data.update(data), any list values will be wrapped
            # in another list. By iterating through the list and updating
            # for each value, we get the expected result of a single list.
            q_data = QueryDict('', mutable=True)
            for key, value in data.iteritems():
                if isinstance(value, list):
                    # need to iterate through the list and upate
                    # so that the list does not get wrapped in an
                    # additional list.
                    for x in value:
                        q_data.update({key: x})
                else:
                    q_data.update({key: value})

            if request.method == 'GET':
                request.GET = q_data

            if request.method == 'POST':
                request.POST = q_data

        return None

The old naive version

class JSONMiddleware(object):
    """
    Process application/json requests data from GET and POST requests.
    """
    def process_request(self, request):
        if 'application/json' in request.META['CONTENT_TYPE']:
            data = urlencode(json.loads(request.body))

            if request.method == 'GET':
                request.GET = QueryDict(data)

            if request.method == 'POST':
                request.POST = QueryDict(data)

        return None

If you add this middleware to your Django install, it will process the JSON data and put it in the GET or POST variable as appropriate. There are, of course, other solutions to this problem, but using this middleware allows you to write you AngularJS or your Django views as intended, passing an object as the data and reading from request.POST.

3 Responses
Add your response

Nice simple workaround. If you do a lot of REST calls with Django, you should also checkout the Django Rest Framework which enable all this natively, and much more!

over 1 year ago ·

@yannikmesserli, that is a really good point. I found this is really useful for those times when I need to write a small little function based view that doesn't need the overhead or is more complex to try to write in the Django Rest Framework. This mostly happened when I was going in an optimizing certain sections that needed to be as fast as possible.

over 1 year ago ·

Here is my code:

class JsonPayloadToRequestDataMiddleware(object):
    def process_request(self, request):

        if request.method != "POST":
            return None

        if 'application/json' not in request.META['CONTENT_TYPE']:
            return None

        body = request.body.strip()
        if not body:
            return None

        is_obj = body.startswith("{") and body.endswith("}")
        is_array = body.startswith("[") and body.endswith("]")
        if not is_obj and not is_array:
            return None

        # data is django.http.QueryDict
        json_data = json.loads(request.body)
        string_data = urllib.urlencode(json_data, True)
        data = QueryDict(string_data, mutable=True)
        if request.POST:
            data.update(request.POST)

        # it should be immutable
        request.POST = data.copy()
over 1 year ago ·