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 how to do this.
In api/urls.py
I have this:
from django.conf.urls import url, include
from rest_framework import routers
from rest_framework.urlpatterns import format_suffix_patterns
import views
router = routers.DefaultRouter()
urlpatterns = [
url(r'^organisation/$', views.organisation),
]
urlpatterns = format_suffix_patterns(urlpatterns,
allowed=['json', 'csv'])
And I have this in api/views.py
:
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
@api_view(['GET'])
def organisation(request, format=None):
code = request.query_params.get('code', None)
print 'format', format
organisation = Organisation.objects.get(code=code)
serializer = OrgSerializer(organisation)
data = serializer.data
return JSONResponse(data)
But if I go to api/1.0/organisation.csv?code=123
, I still see:
format json
in the console.
What am I doing wrong? And how should I return CSV once I have managed to capture the format? (I suspect I'm probably doing the wrong thing by writing my own JSONResponse
, already.)
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.
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