Returning CSV format from django-rest-framework?

2019-05-01 12:26发布

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

3条回答
在下西门庆
2楼-- · 2019-05-01 12:33

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.

查看更多
ら.Afraid
3楼-- · 2019-05-01 12:36

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
查看更多
男人必须洒脱
4楼-- · 2019-05-01 12:43

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.

查看更多
登录 后发表回答