2010-11-01 11 views
7

All'interno di my view.py, ho due funzioni, una che elabora l'input da un modulo e genera un elenco filtrato e un altro che deve esportare questo elenco in CSV.Generazione di file CSV con Django (contenuto dinamico)

Ecco il ritorno del mio prima funzione:

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

Ecco la funzione di esportazione:

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 

non sono sicuro di come ottenere il set di query dalla mia prima funzione, che contiene un elenco degli elementi che voglio nel mio CSV e lo uso nella mia funzione export_to_csv. Oppure sarebbe il modo migliore di combinare queste due funzioni e fare clic su una casella di controllo se desidera scaricare un file CSV. Qualsiasi aiuto sarebbe apprezzato.

risposta

7

mi consiglia che unisce questi in una funzione di visualizzazione che prende un parametro aggiuntivo:

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)) 

Poi, nel vostro urls.py, mettere qualcosa di simile nel tuo urlpatterns:

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

Ho provato in questo modo, ma quando faccio clic sul mio pulsante "export", che va all'url: localhost: 8000/cdr/export_csv, perde tutte le richieste GET e di conseguenza non c'è elaborazione di queryset, quindi il mio Il file CSV è vuoto. Quindi, come può il mio pulsante "Esporta" inviare tutte le richieste come se clicchi sul mio pulsante "cerca"? – chiurox

+0

Il pulsante Esporta deve 1) indirizzare l'URL di esportazione e includere i parametri di query oppure 2) essere parte di un modulo che ha i parametri di query, come campi nascosti se necessario. È difficile per me formulare una raccomandazione specifica poiché non sono completamente chiaro su come le tue pagine si relazionano tra loro. –

+0

Sì, ho deciso di farlo nel modo che hai descritto come prima opzione. Ora 'i campi nascosti', è interessante, lo guarderò più tardi quando incontrerò una situazione simile. – chiurox

4

IMHO, il migliore sarebbe combinarli e generare i dati CSV da un queryset esplicito. Questo potrebbe quindi essere riscritto per qualcosa di generale come (non testato):

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 

che è possibile utilizzare in questo modo:

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

-

Il codice di esempio che hai fornito assume la QuerySet è impostato nei dati della sessione, che potrebbe causare un sacco di bug e problemi di sicurezza. Se memorizzi sessioni nel tuo database, potresti finire a leggere i dati, solo per riscriverli in una forma molto meno efficiente.

0

Ho trovato un modo per farlo diverso da quello di knutin. Ho dichiarato una lista vuota chiamata csv_list = [] al di fuori delle mie funzioni, o variabile globale.

Nella mia funzione principale (quella che elabora e filtra in base all'input dell'utente), trasformo questa csv_list globale in modo che sia impostata sulla versione "aggiornata" del queryset. Poi per generare il csv, è facile come: per la chiamata in csv_list: writer.writerow ([call.src, call.dst]) Risposta ritorno

Sta funzionando ragionevolmente ora.

+0

E 'pericoloso usare globali per passare i dati tramite una vista ; Django può essere infilato e probabilmente si interromperà con l'implementazione. Non vedrai questo bug durante il test da solo, e dal momento che si basa su una race condition, rintracciarlo sarà difficile. –

+0

Potresti approfondire la pericolosità e il modo in cui si potrebbe interrompere la distribuzione? – chiurox

+0

L'utente 1 pubblica una richiesta per il modulo. Questo chiama la funzione view che imposta 'csv_list'. L'utente 2 fa la stessa cosa, che imposta di nuovo 'csv_list'. L'utente 1 esporta quindi il CSV e ottiene i dati dell'utente 2 tramite 'csv_list'. –

0

Il seguente prende un queryset Django e sputa un file CSV.

Usage ::

da utils importare dump2csv

da dummy_app.models import *

Qs = DummyModel.objects.tutto()

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

Lo 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) 
Problemi correlati