Skip to content

Instantly share code, notes, and snippets.

@LucasRoesler
Last active June 27, 2023 17:01
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save LucasRoesler/700d281d528ecb7895c0 to your computer and use it in GitHub Desktop.
Save LucasRoesler/700d281d528ecb7895c0 to your computer and use it in GitHub Desktop.
A Django middleware that process JSON data into the appropriate GET or POST variable. I use this with AngularJS, by default POST requests are sent as JSON instead of the urlencoded data expected by Django.
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
@dusan87
Copy link

dusan87 commented Jun 21, 2015

There is a KeyError exception in case there is no content_type key/value pair in request. I'd recommend you just to put try except block to catch this error and return None as well

@hanuprateek
Copy link

hanuprateek commented May 3, 2016

Thank you for the gist i was previously using a transform request in my angular scripts but this is better
Yes like dusan87 mentioned django throws an error in case no 'CONTENT_TYPE' key is present in the request.
You can use a try and except as suggested or just add request.META.get('CONTENT_TYPE') to the if condition.
For example a statement like,

if request.META.get('CONTENT_TYPE') and 'application/json' in request.META.get('CONTENT_TYPE'):
...

@Coder1400
Copy link

Coder1400 commented Jun 5, 2018

For completeness' sake, import json and QueryDict

@vaurelios
Copy link

from django.http import HttpResponse, QueryDict

import json


class JSONMiddleware:
    """
    Process application/json requests data from GET and POST requests.
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.META.get('CONTENT_TYPE') and 'application/json' in request.META.get('CONTENT_TYPE'):
            try:
                data = json.loads(request.body)

                q_data = QueryDict('', mutable=True)
                for key, value in data.items():
                    if isinstance(value, 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 self.get_response(request)
            except json.JSONDecodeError:
                return HttpResponse("JSON Decode Error", status=400)

        return self.get_response(request)

Updated to Django 2.2 and Python 3 and applied all comments suggestions. Also return a "Bad Request" in case of JSON parsing problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment