reactjsdjangodatabasereact-nativefrontend

Possible to use axios/fetch to open page in new window in order to download csv from api view?


I have a Django view that downloads a large dataset from a rest api to a local .csv using StreamingHttpResponse. This works great; however, when I try to add authentication with [IsAuthenticated] permissions_classes tag, the url (of course) becomes unvisitable without including a valid user Bearer token in the header.

Here is the relevant code from views.py:

import csv
from django.http import StreamingHttpResponse

class Echo:
    def write(self, value):
        return value

def streaming_csv_view(request):
    queryset = Emissions.objects.all().values_list('year', 'value')
    echo_buffer = Echo()
    csv_writer = csv.writer(echo_buffer)
    labels=[('Year', 'Value')]
    rows = (csv_writer.writerow(row) for row in chain(labels,queryset))

    response = StreamingHttpResponse(rows, content_type="text/csv")
    response["Content-Disposition"] = 'attachment; filename="Emissions.csv"'
    return response

I achieve this elsewhere in my code for more standard API calls (i.e. retrieving data), but can't wrap my head around how to make this work for my csv download, which requires that the user visit the page... Can I use a fetch/axios call to open this page in a new window to initiate the download and then close the window when the download is complete? I'm having trouble finding examples of axios being used in this way

I feel like I'm missing something...any help would be greatly appreciated.

Here's a typical fetch GET request to the endpoint, which won't work...

const fetchData = async() => {

        url = `link/api/export-emissions`

        try{
            const response = await fetch(url,{
                method:'GET',
                headers:{
                'Content-Type':'application/json',
                'Authorization':'Bearer ' + String(authTokens.access)
                }
            })


        }catch (e){
        console.log(e)
        }

        }

Solution

  • i am assuming that your url is working fine however you can try this approach of downloading the csv file using your url and axios.

    axios
    .get("--your-url---", {   // eg.https://picsum.photos/800/800 (no auth required)
    responseType: "blob",
    headers: {
      Authorization: `Bearer YOUR_TOKEN_HERE`, //add your token here
    },
    onDownloadProgress: function (progressEve) {
      console.log(
        ((progressEve.loaded / progressEve.total) * 100).toFixed() + "%"
      );
    },
    })
    .then((object) => {
    const url = URL.createObjectURL(object.data);
    const anchor = document.createElement("a");
    anchor.href = url;
    
    anchor.download = "name_of_file.extension";  //add name and extension
    anchor.style.display = "none";
    document.body.appendChild(anchor);
    anchor.click();
    anchor.remove();
    URL.revokeObjectURL(url);
    })
    .catch((error) => console.log(error));