Added a multipart parser that attempts to parse nested strings as json.
Some checks failed
StarFields Django Rest Framework Generics / build (push) Failing after 12s
Some checks failed
StarFields Django Rest Framework Generics / build (push) Failing after 12s
This commit is contained in:
73
starfields_drf_generics/parsers.py
Normal file
73
starfields_drf_generics/parsers.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from rest_framework.parsers import BaseParser, DataAndFiles
|
||||
from django.http.multipartparser import MultiPartParserError
|
||||
from rest_framework.exceptions import ParseError
|
||||
from django.http.multipartparser import \
|
||||
MultiPartParser as DjangoMultiPartParser
|
||||
from django.conf import settings
|
||||
import json
|
||||
|
||||
|
||||
class NestedJsonMultiPartParser(BaseParser):
|
||||
"""
|
||||
Parser for multipart form data, which may include file data.
|
||||
"""
|
||||
media_type = 'multipart/form-data'
|
||||
|
||||
def parse(self, stream, media_type=None, parser_context=None):
|
||||
"""
|
||||
Parses the incoming bytestream as a multipart encoded form,
|
||||
and returns a DataAndFiles object.
|
||||
The main difference with the parser from rest_framework.parsers
|
||||
is that it attempts to parse nested strings as json to fit with
|
||||
better with json payloads. I also ensure that a single file is
|
||||
passed per field instead of a list which was erroring out
|
||||
FieldFile.to_internal_value.
|
||||
|
||||
`.data` will be a dict containing all the form parameters.
|
||||
`.files` will be a dict containing all the form files.
|
||||
"""
|
||||
parser_context = parser_context or {}
|
||||
request = parser_context['request']
|
||||
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
|
||||
meta = request.META.copy()
|
||||
meta['CONTENT_TYPE'] = media_type
|
||||
upload_handlers = request.upload_handlers
|
||||
|
||||
try:
|
||||
parser = DjangoMultiPartParser(meta,
|
||||
stream,
|
||||
upload_handlers,
|
||||
encoding)
|
||||
data, files = parser.parse()
|
||||
|
||||
# Attempt to parse the multipart fields as json, this is not
|
||||
# demanding since multiparts exist exclusively for file uploads
|
||||
# which is much more demanding
|
||||
data_dict = {}
|
||||
for key in data.keys():
|
||||
values = data[key]
|
||||
try:
|
||||
data_dict[key] = json.loads(values)
|
||||
except Exception as e:
|
||||
data_dict[key] = values
|
||||
|
||||
# Make sure the filenames become file names
|
||||
for filename in files.keys():
|
||||
uploaded_file = files[filename]
|
||||
hasfilename = hasattr(uploaded_file, '_name')
|
||||
hasname = hasattr(uploaded_file, 'name')
|
||||
if hasfilename and not hasname:
|
||||
uploaded_file.name = uploaded_file._name
|
||||
|
||||
# Turn the monstrous MultiValueDict into a normal dict so that
|
||||
# there is only a single uploaded file per field passed
|
||||
files_dict = {}
|
||||
for key in files.keys():
|
||||
uploaded_file = files[key]
|
||||
if isinstance(uploaded_file, list):
|
||||
uploaded_file = uploaded_file[0]
|
||||
files_dict[key] = uploaded_file
|
||||
|
||||
return DataAndFiles(data_dict, files_dict)
|
||||
except MultiPartParserError as exc:
|
||||
raise ParseError('Multipart form parse error - %s' % str(exc))
|
||||
Reference in New Issue
Block a user