0
votes

I am taking queryset turning into csv file, I am even getting the response back. But the browser is not downloading the returned csv file. I am on chrome.

class CSVMixin(object):
csv_filename = 'csvfile.csv'

def get_csv_filename(self):
    return self.csv_filename

def render_to_csv(self, queryset):
    response = HttpResponse(content_type='text/csv')
    cd = 'attachment; filename="{0}"'.format(self.get_csv_filename())
    response['Content-Disposition'] = cd

    headers = queryset[0].keys()
    dict_writer = csv.DictWriter(response, fieldnames=headers)

    dict_writer.writeheader()
    dict_writer.writerows(queryset)
    return response

class EmailCampaignViewSet(CSVMixin, OrionAdminModelViewset):
    queryset = MyObject.objects.all()

    pagination_class = DefaultLimitOffsetPagination
    filter_class = EmailCampaignFilter

    @list_route()
    def report(self, request):
        query = self.request.query_params
        data_format = query['data_format'] if query['data_format'] else None

        if data_format == 'csv':
            return self.render_to_csv(queryset)

When I call the report route, I get the csv formatted text in my response. But it is not triggering the download.

Here is my request from react:

this.getReport = (format="json") => {
        this.setState({btnDisabled: true});
        const requestObj = {
            method: 'GET',
            headers: {
                'Authorization': 'Token ' + this.props.session_token,
                'Content-Type': 'application/json',
            }
        };

        const uri = new URI(`${API_ENDPOINT}/email-campaign/report`);
        const campaigns = this.state.campaignList.map((campaign)=>(
            campaign.value
        ));
        uri.setSearch({
            campaigns: [campaigns],
            date_from: stringToDateISOString(this.state.dateFrom),
            date_to: stringToDateISOString(this.state.dateTo),
            data_format: format,
        });
        return fetch(uri.toString(), requestObj).then(restJSONResponseToPromise).then(responseJSON => {
            if (responseJSON.results){
                this.setState({report: responseJSON.results, btnDisabled: false});
            }
        }, (response) => {
            clearSessionIfInvalidToken(this.props.clearSession);
            this.setState({btnDisabled: false});
        });
    }

Response Headers:

HTTP/1.0 200 OK

Date: Mon, 12 Jun 2017 19:58:03 GMT

Server: WSGIServer/0.2 CPython/3.5.3

Content-Type: text/csv

X-Frame-Options: SAMEORIGIN

Access-Control-Allow-Origin: http://localhost:3000

Vary: Accept, Origin

Allow: GET, OPTIONS

Content-Disposition: attachment; filename=emailcampaign_export.csv;

Cache-Control: no-cache

1
Your mixin looks correct. Where is data_format defined in your view? Are you sure it's not erroring out?Brobin
I am not erroring out, i forgot to include that line in the question. I got http response of 200, with the expected csv on the response body. Its just the file not being downloaded into my system.Rakin Alam
does the http response have a Content-Disposition header? developer.mozilla.org/en-US/docs/Web/HTTP/Headers/…Håken Lid
Yes it has the following headers: HTTP/1.0 200 OK Date: Mon, 12 Jun 2017 19:58:03 GMT Server: WSGIServer/0.2 CPython/3.5.3 Content-Type: text/csv X-Frame-Options: SAMEORIGIN Access-Control-Allow-Origin: localhost:3000 Vary: Accept, Origin Allow: GET, OPTIONS Content-Disposition: attachment; filename=emailcampaign_export.csv; Cache-Control: no-cacheRakin Alam
I'd add react and javascript tags to the question. I'm not as experienced in those and it sounds like that may be causing the issue if the response is being returned correctly.Brobin

1 Answers

0
votes

Try this:

from cStringIO import StringIO

def render_to_csv(self, queryset):
    file_io = StringIO()
    headers = queryset[0].keys()
    dict_writer = csv.DictWriter(file_io, fieldnames=headers)
    dict_writer.writeheader()
    dict_writer.writerows(queryset)
    response = HttpResponse(file_io.getvalue(), content_type='text/csv')
    file_io.close()
    cd = 'attachment; filename="{0}"'.format(self.get_csv_filename())
    response['Content-Disposition'] = cd
    return response