Returning CSV format from django-rest-framework?

前端 未结 4 2182
囚心锁ツ
囚心锁ツ 2021-02-13 22:23

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

相关标签:
4条回答
  • 2021-02-13 23:02

    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
    
    0 讨论(0)
  • 2021-02-13 23:13

    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.

    0 讨论(0)
  • 2021-02-13 23:14

    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.

    0 讨论(0)
  • 2021-02-13 23:27

    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.

    0 讨论(0)
提交回复
热议问题