Home > Net >  download to csv the result of a search in Django
download to csv the result of a search in Django

Time:04-29

I am trying to download a CSV from the result of a search as an option. Meaning that the user can do a search and view the result in a template, and then download the csv for that search result if needed. The templates are not the issue, it's the views I need to resolve. I have the following views:

First is the search view

def binder_search(request):
    if request.method == "POST":
        searched = request.POST['searched']
        binders_searched = Binders.objects.filter(Q(description__contains=searched) | Q(step__name__contains=searched) | Q(status__name__contains=searched))

        return render(request, "binder_search.html", {'searched': searched, 'binders_searched': binders_searched})

    else:
        return render(request, "binder_search.html", {})

Then is the csv. This view creates the list of all items in the database. What I am trying to do is get the search result from the above view, and then create the csv file. I would end up with a CSV file that has only the search result in it.

def binders_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename=binders_result.csv'

    # create a csv writer
    writer = csv.writer(response)

    # designate the model
    binders = Binders.objects.all()

    # add column at the heading of csv file
    writer.writerow(['Item Code', 'Description', 'Item Type', 'Current Step', 'Current Status', 'Last change by'])

    # loop thru and output
    for binder in binders:
        writer.writerow([binder.itemcode, binder.description, binder.itemtype, binder.step, binder.status, binder.user])

    return response

I looked around at different solutions, but none actually debugged me. Any idea how to do this?

CodePudding user response:

What am I missing? Can't you just combine the two?

def binder_search(request):
    if request.method != "POST":
        return render(request, "binder_search.html", {})

    # POST

    searched = request.POST['searched']
    binders_searched =   Binders.objects.filter(Q(description__contains=searched) | Q(step__name__contains=searched) | Q(status__name__contains=searched))

    # create a csv writer with header writing to response
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename=binders_result.csv'
    writer = csv.writer(response)
    writer.writerow(['Item Code', 'Description', 'Item Type', 'Current Step', 'Current Status', 'Last change by'])

    # loop thru filtered results and output
    for binder in binders_searched:
        writer.writerow(
            [binder.itemcode, binder.description, binder.itemtype, binder.step, binder.status, binder.user]
        )
    return response

CodePudding user response:

Here is a solution that works--done with the help of nigel222 and the session framework (request.session). This solution provides the views needed for displaying a search result into a template, and then press a button or link to download that exact result into a CSV format. Therefore, the user can get a search result, and then download the result if he wants to. I have been looking around but couldn't find a similar solution, so I am posting it here for others.

The first view (binder_search) does the search and use request.session to cache the variable "searched".

def binder_search(request):
    if request.method == "GET":
        searched = request.GET['searched']

        # Cache variable "searched" for views.binder_search_csv
        request.session['searched'] = searched

        # multiple columns
        binders_searched = Binders.objects.filter(Q(description__contains=searched) | Q(step__name__contains=searched) | Q(status__name__contains=searched))
        return render(request, "binder_search.html", {'searched': searched, 'binders_searched': binders_searched})
    
    else:
        return render(request, "binder_search.html", {})

The second view use the cached variable "searched" from the above view and download the search result to a csv file.

def binder_search_csv(request):
    if request.method != "GET":
        return render(request, "binder_search.html", {})

    # Use cached variable from views.binder_search
    searched = request.session['searched']

    binders_searched = Binders.objects.filter(Q(description__contains=searched) | Q(step__name__contains=searched) | Q(status__name__contains=searched))

    # create a csv writer with header writing to response
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename=binders_result.csv'
    writer = csv.writer(response)
    writer.writerow(['Item Code', 'Description', 'Item Type', 'Current Step', 'Current Status', 'Last change by'])

    # loop thru filtered results and output
    for binder in binders_searched:
        writer.writerow(
            [binder.itemcode, binder.description, binder.itemtype, binder.step, binder.status, binder.user]
        )
    return response

There might be ways to streamline these two views but as they are right now, they work totally fine.

  • Related