I have a working Django 1.8 site, and I want to add a RESTful API using django-rest-framework. I would like to support rendering to CSV and JSON formats, and am puzzling over ho
If you just need to download CSV (without Model serialization etc)
import csv
from django.http import HttpResponse
from rest_framework.views import APIView
class CSVviewSet(APIView):
def get(self, request, format=None):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="export.csv"'
writer = csv.DictWriter(response, fieldnames=['emp_name', 'dept', 'birth_month'])
writer.writeheader()
writer.writerow({'emp_name': 'John Smith', 'dept': 'Accounting', 'birth_month': 'November'})
writer.writerow({'emp_name': 'Erica Meyers', 'dept': 'IT', 'birth_month': 'March'})
return response
Got it. The trick is to install djangorestframework-csv, then add the following in settings:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
'rest_framework_csv.renderers.CSVRenderer',
),
}
And then scrap the JSONResponse
function in views.py
and just do return Response(serializer.data)
instead. Very easy in the end.
This is an old post, but I've seen the accepted answer sets the CSVRenderer
as one of the defaults, which is not usually wanted.
I would implement the view this way:
...
from rest_framework.viewsets import ModelViewSet
from rest_framework.settings import api_settings
from rest_framework_csv.renderers import CSVRenderer
from .... import OrgSerializer
...
class OrganizationViewSet(ModelViewSet):
queryset = Organisation.objects.all()
http_method_names = ['get', '...list all the other verbs you want']
serializer_class = OrgSerializer
renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (CSVRenderer,)
def get_queryset(self):
if 'code' in self.request.GET:
code = self.request.GET['code']
return Organisation.objects.filter(code=code)
return Organisation.objects.all()
Of course, having the django-rest-framework-csv
installed and OrgSerializer
defined somewhere.
Then you can just set 'rest_framework.renderers.JSONRenderer'
as your default renderer in settings and the rest framework will automatically return csv content if you request it on the HTTP_ACCEPT
header - just for this view.
I think that a StreamingHttpResponse
should be the preferred way. With django-storages
and ViewSet
it looks more or less like this.
@action(detail=True, methods=["get"])
def download(self, request, pk=None):
f = self.get_object()
response = StreamingHttpResponse(
streaming_content=f.file.chunks(), content_type="text/csv"
)
response[
"Content-Disposition"
] = f'attachment; filename="{f.name}.csv"'
response.status_code = status.HTTP_200_OK
return response
Also, FileResponse
is basically a StreamingHttpResponse
with some headers etc so both are great for this use case.