Created
February 20, 2018 01:26
-
-
Save pansapiens/81ccbccf32e2cf9b03dc6cb872ab505b to your computer and use it in GitHub Desktop.
Django REST Framework CSV parser, RFC 4180
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Dict, List | |
import csv | |
from rest_framework import status | |
from rest_framework.response import Response | |
from rest_framework.parsers import JSONParser, BaseParser | |
from rest_framework.views import APIView | |
class CSVTextParser(BaseParser): | |
""" | |
A CSV parser for DRF APIViews. | |
Based on the RFC 4180 text/csv MIME type, but extended with | |
a dialect. | |
https://tools.ietf.org/html/rfc4180 | |
""" | |
media_type = 'text/csv' | |
def parse(self, stream, media_type=None, parser_context=None) -> List[List]: | |
""" | |
Return a list of lists representing the rows of a CSV file. | |
""" | |
# return list(csv.reader(stream, dialect='excel')) | |
charset = 'utf-8' | |
media_type_params = dict([param.strip().split('=') for param in media_type.split(';')[1:]]) | |
charset = media_type_params.get('charset', 'utf-8') | |
dialect = media_type_params.get('dialect', 'excel') | |
txt = stream.read().decode(charset) | |
csv_table = list(csv.reader(txt.splitlines(), dialect=dialect)) | |
return csv_table | |
class CsvCreate(APIView): | |
parser_classes = (CSVTextParser,) | |
def post(self, request, version=None): | |
""" | |
Recieves a request body containing CSV, using the `text/csv` content-type, | |
as in: https://tools.ietf.org/html/rfc4180 | |
Can also recieve a CSV file via 'multipart/form-data'. | |
""" | |
content_type = request.content_type.split(';')[0].strip() | |
encoding = 'utf-8' | |
if content_type == 'text/csv': | |
csv_table = request.data | |
# In this example, we just return the parsed CSV data structure, | |
# but in a view with an associated model and/or serializer we could | |
# do something more interesting with it (eg create a new database record). | |
return Response(csv_table, status=status.HTTP_200_OK) | |
elif content_type == 'multipart/form-data': | |
fh = request.data.get('file', None) | |
csv_table = fh.read().decode(encoding) | |
return Response(csv_table, status=status.HTTP_200_OK) | |
else: | |
return Response(None, status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE) | |
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment