chiurox
chiurox

Reputation: 1619

Generating CSV file with Django (dynamic content)

Inside my view.py, I have two functions, one that processes input from a form and outputs a filtered list, and another that is supposed to export this list to CSV.

Here is the return of my first function:

return render_to_response('templateX.html',
{
 'queryset': queryset,
 'filter_form': filter_form,
 'validated': validated,
},
 context_instance = RequestContext(request)
 )

Here is the exporting function:

def export_to_csv(request):
    # get the response object, this can be used as a stream.
    response = HttpResponse(mimetype='text/csv')
    # force download.
    response['Content-Disposition'] = 'attachment;filename=export.csv'
    # the csv writer
    writer = csv.writer(response)
    qs = request.session['queryset']
    for cdr in qs:
        writer.writerow([cdr['calldate'], cdr['src'], cdr['dst'], ])
    return response   

I'm not sure how to get the queryset from my first function, which contains a list of the items I want in my CSV and use it in my export_to_csv function. Or would the best way be combining these two functions and have the user click on a checkbox whether he/she wants to download a CSV file. Any help would be appreciated.

Upvotes: 7

Views: 13692

Answers (4)

Armance
Armance

Reputation: 5390

The following takes in a Django queryset and spits out a CSV file.

Usage::

from utils import dump2csv

from dummy_app.models import *

qs = DummyModel.objects.all()

dump2csv.dump(qs, './data/dump.csv')

The script:

import csv
from django.db.models.loading import get_model

def dump(qs, outfile_path):

    model = qs.model
writer = csv.writer(open(outfile_path, 'w'))

headers = []
for field in model._meta.fields:
    headers.append(field.name)
writer.writerow(headers)

for obj in qs:
    row = []
    for field in headers:
        val = getattr(obj, field)
        if callable(val):
            val = val()
        if type(val) == unicode:
            val = val.encode("utf-8")
        row.append(val)
    writer.writerow(row)

Upvotes: 0

Mike DeSimone
Mike DeSimone

Reputation: 42805

I'd recommend combining these into one view function which takes an extra parameter:

def my_view(request, exportCSV):
    # ... Figure out `queryset` here ...

    if exportCSV:
        response = HttpResponse(mimetype='text/csv')
        response['Content-Disposition'] = 'attachment;filename=export.csv'
        writer = csv.writer(response)
        for cdr in queryset:
            writer.writerow([cdr['calldate'], cdr['src'], cdr['dst'], ])
        return response
    else:
        return render_to_response('templateX.html', {'queryset': queryset,
            'filter_form': filter_form, 'validated': validated},
            context_instance = RequestContext(request))

Then, in your urls.py, put something like this in your urlpatterns:

url(r'^form', 'my_view', {"exportCSV": False}, name="form"),
url(r'^csv', 'my_view', {"exportCSV": True}, name="export"),

Upvotes: 7

chiurox
chiurox

Reputation: 1619

I found a way to do it that's different than knutin's. I declared an empty list called csv_list = [] outside my functions, or global variable.

In my main function (the one that processes and filters based on user input), I make this csv_list global so that it gets set to the "updated" version of the queryset. Then to generate the csv, it's as easy as: for call in csv_list: writer.writerow([call.src, call.dst]) return response

It's working reasonably now.

Upvotes: 0

knutin
knutin

Reputation: 5103

IMHO, the best would be to combine them and generate the CSV data from an explicit queryset. This could then be rewritten to something general like(not tested):

def export_to_csv(request, queryset, fields):
    response = ...
    writer = csv.writer(response)
    for obj in queryset:
        writer.writerow([getattr(obj, f) for f in fields])
    return response

Which you can use like this:

def my_view(request):
    calls = Call.objects.all()
    return export_to_csv(request, calls, fields = ('calldate', 'src', 'dst'))

--

The example code you provided assumes the QuerySet is set in the session data, which could cause you tons of bugs as well as security problems. If you store sessions in your database, you could end up reading data, just to write it back in a much less efficient form.

Upvotes: 4

Related Questions