Files
starfields-drf-generics/starfields_drf_generics/parsers.py
Anastasios Svolis a380800285
Some checks failed
StarFields Django Rest Framework Generics / build (push) Failing after 12s
Added a multipart parser that attempts to parse nested strings as json.
2025-01-11 00:19:46 +02:00

74 lines
3.0 KiB
Python

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))