Skip to content

Instantly share code, notes, and snippets.

@pansapiens
Created February 20, 2018 01:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pansapiens/81ccbccf32e2cf9b03dc6cb872ab505b to your computer and use it in GitHub Desktop.
Save pansapiens/81ccbccf32e2cf9b03dc6cb872ab505b to your computer and use it in GitHub Desktop.
Django REST Framework CSV parser, RFC 4180
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