download to csv the result of a search in Django
Asked Answered
E

2

0

I am trying to download a CSV from the result of a search, as an option. Meaning that the user should be able to do a search and view the result in a template, and then download the csv for that search result as 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?

Experienced answered 27/4, 2022 at 21:37 Comment(0)
E
0

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.

Experienced answered 28/4, 2022 at 15:35 Comment(0)
B
1

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
Bergess answered 28/4, 2022 at 8:44 Comment(1)
Thank you for that solution. I missed stating that I needed to download the search result to csv using a button if the user wanted to do so. Therefore, the search can be done without creating the csv. My difficulty is using the search result already created, and then create the csv afterward, in that sequence. Not creating the csv automatically.Experienced
E
0

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.

Experienced answered 28/4, 2022 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.