2010-11-01 12 views
7

Wewnątrz mojego pliku view.py mam dwie funkcje, jedną, która przetwarza dane wejściowe z formularza i wyświetla przefiltrowaną listę, a drugą, która ma wyeksportować tę listę do pliku CSV.Generowanie pliku CSV za pomocą Django (zawartość dynamiczna)

Oto powrót mojej pierwszej funkcji:

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

Oto funkcja eksportujący:

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 

Nie jestem pewien, jak uzyskać queryset z mojej pierwszej funkcji, który zawiera listę elementów, które chcę w moim pliku CSV i wykorzystuję w funkcji export_to_csv. A może najlepszym sposobem byłoby połączenie tych dwóch funkcji i aby użytkownik kliknął pole wyboru, czy chce pobrać plik CSV. Każda pomoc będzie doceniona.

Odpowiedz

7

Polecam łącząc je w jednej funkcji widoku, który bierze dodatkowy parametr:

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

Następnie w swojej urls.py, umieścić coś takiego w swoim urlpatterns:

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

Próbowałem go w ten sposób, ale kiedy klikam na mój przycisk "eksport", który przechodzi do adresu URL: localhost: 8000/cdr/export_csv, to traci wszystkie żądania GET iw konsekwencji nie ma przetwarzania zapytania, więc mój Plik CSV jest pusty. Jak więc mój przycisk "eksportuj" może wysłać wszystkie zapytania, tak jakbym kliknął przycisk "szukaj"? – chiurox

+0

Przycisk Eksportuj powinien 1) adresować eksportowany adres URL i zawierać parametry zapytania lub 2) być częścią formularza, który ma parametry zapytania, jako ukryte pola, jeśli to konieczne. Trudno jest mi przedstawić konkretne zalecenie, ponieważ nie jestem całkowicie pewien, w jaki sposób twoje strony odnoszą się do siebie nawzajem. –

+0

Tak, zdecydowałem się zrobić to tak, jak opisałeś jako swoją pierwszą opcję. Teraz "ukryte pola", ciekawe, na to później przyjrzę się, gdy natknę się na podobną sytuację. – chiurox

4

IMHO, najlepiej byłoby je połączyć i wygenerować dane CSV z jawnego zestawu zapytań. To może następnie zostać przepisany na coś jak generał (nie testowane):

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 

których można używać tak:

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

-

Przykładowy kod podałeś zakłada QuerySet jest ustawić w danych sesji, co może spowodować mnóstwo błędów, a także problemy z bezpieczeństwem. Jeśli przechowujesz sesje w bazie danych, możesz skończyć odczyt danych, po prostu zapisać je w znacznie mniej wydajnej formie.

0

Znalazłem sposób na zrobienie czegoś innego niż knutin. Deklarowałem pustą listę o nazwie csv_list = [] poza moimi funkcjami lub zmienną globalną.

W mojej głównej funkcji (tej, która przetwarza i filtruje na podstawie danych wprowadzonych przez użytkownika), robię tę csv_list globalną, aby została ustawiona na "zaktualizowaną" wersję zestawu zapytań. Następnie w celu wygenerowania pliku CSV, to tak proste, jak: dla wywołania w csv_list: writer.writerow ([call.src, call.dst]) Pasmo powrót

To działa rozsądnie teraz.

+0

To niebezpieczne w użyciu globalnych do przekazywania danych przez widoki ; Django można wklejać, co prawdopodobnie przerwie wdrażanie. Nie zobaczysz tego błędu podczas testowania na własną rękę, a ponieważ jest on oparty na warunkach wyścigowych, śledzenie go będzie trudne. –

+0

Czy mógłbyś bardziej szczegółowo opisać niebezpieczeństwa i sposób, w jaki może on przerwać wdrażanie? – chiurox

+0

Użytkownik 1 wysyła prośbę o formularz. To wywołuje twoją funkcję widoku, która ustawia 'csv_list'. Użytkownik 2 robi to samo, co ponownie ustawia 'csv_list'. Użytkownik 1 następnie eksportuje plik CSV i pobiera dane użytkownika 2 za pośrednictwem 'csv_list'. –

0

Poniższy przyjmuje zestaw zapytań Django i wypluwa plik CSV.

Zastosowanie ::

z utils import dump2csv

z dummy_app.models import *

qs = DummyModel.objects.wszystko()

dump2csv.dump (QS './data/dump.csv')

Skrypt:

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) 
Powiązane problemy