2010-06-03 9 views
7

Ich frage mich, ob jemand mit einem besseren Verständnis von Python und Gae kann mir dabei helfen. Ich lade eine CSV-Datei von einem Formular in den gae-Datenspeicher hoch.Hochladen und Parsen CSV-Datei mit Google App-Engine

class CSVImport(webapp.RequestHandler): 
    def post(self): 
    csv_file = self.request.get('csv_import') 
    fileReader = csv.reader(csv_file) 
    for row in fileReader:  
     self.response.out.write(row) 

ich in das gleiche Problem laufen, dass jemand anderes hier erwähnt - http://groups.google.com/group/google-appengine/browse_thread/thread/bb2d0b1a80ca7ac2/861c8241308b9717

Das heißt, die csv.reader über jedes Zeichen iteriert und nicht die Linie. Ein Google-Techniker hat diese Erklärung verlassen:

Der Aufruf self.request.get ('csv') gibt einen String zurück. Wenn Sie über eine Zeichenfolge iterieren, durchlaufen Sie die Zeichen, nicht die Zeilen. Sie können die Unterschied hier:

class ProcessUpload(webapp.RequestHandler): 
    def post(self): 
    self.response.out.write(self.request.get('csv')) 
    file = open(os.path.join(os.path.dirname(__file__), 'sample.csv')) 
    self.response.out.write(file) 

    # Iterating over a file 
    fileReader = csv.reader(file) 
    for row in fileReader: 
     self.response.out.write(row) 

    # Iterating over a string 
    fileReader = csv.reader(self.request.get('csv')) 
    for row in fileReader: 
     self.response.out.write(row) 

ich wirklich nicht folgen die Erklärung, und war nicht erfolgreich es umzusetzen. Kann jemand eine klarere Erklärung dafür und eine vorgeschlagene Lösung liefern?

Danke, August

Antwort

13

Kurze Antwort, versuchen Sie dies:

fileReader = csv.reader(csv_file.split("\n")) 

Lange Antwort, sollten Sie Folgendes beachten:

for thing in stuff: 
    print thing.strip().split(",") 

Wenn Sachen ein Dateizeiger ist, jedes Ding eine Linie ist. Wenn Zeug eine Liste ist, ist jedes Ding ein Gegenstand.Wenn Zeug eine Zeichenfolge ist, ist jedes Ding ein Zeichen.

Das Iterieren über das von csv.reader zurückgegebene Objekt wird Ihnen ein Verhalten geben, das dem Iterieren über das übergebene Objekt nur bei jedem CSV-analysierten Objekt ähnelt. Wenn Sie über eine Zeichenfolge iterieren, erhalten Sie eine CSV-analysierte Version jedes Zeichens.

+0

Danke für die Erklärung, es macht mir jetzt viel mehr Sinn. –

+0

Ich würde die Verwendung von .splitlines() anstelle von .split ('\ n') in Betracht ziehen –

8

ich eine deutlichere Erklärung nicht als das, was Sie die Google-Ingenieur sagte erwähnt denken kann. Also lasst uns das ein bisschen unterbrechen.

Das Modul Python csv arbeitet mit dateiähnlichen Objekten, das ist eine Datei oder etwas, das sich wie eine Python-Datei verhält. Daher erwartet csv.reader() ein Dateiobjekt als einzigen erforderlichen Parameter zu erhalten.

Das Anforderungsobjekt webapp.RequestHandler bietet Zugriff auf die HTTP-Parameter, die im Formular bereitgestellt werden. In HTTP werden Parameter als Schlüssel/Wert-Paare bereitgestellt, z. B. csv=record_one,record_two. Wenn Sie self.request.get('csv') aufrufen, gibt das den Wert zurück, der dem Schlüssel csv als eine Python-Zeichenfolge zugeordnet wird. Eine Python-Zeichenfolge ist kein dateiähnliches Objekt. Offensichtlich fällt das Modul csv zurück, wenn es das Objekt nicht versteht und es einfach iteriert (in Python können Strings iteriert werden, z. B. for c in 'Test String': print c wird jedes Zeichen in der Zeichenfolge in einer separaten Zeile ausgeben).

Glücklicherweise bietet Python eine StringIO-Klasse, die es ermöglicht, eine Zeichenfolge als ein dateiähnliches Objekt zu behandeln. So (GAE Annahme unterstützt StringIO, und es gibt keinen Grund, es sollte nicht), sollten diese in der Lage sein zu tun:

class ProcessUpload(webapp.RequestHandler): 
    def post(self): 
    self.response.out.write(self.request.get('csv')) 

    # Iterating over a string as a file 
    stringReader = csv.reader(StringIO.StringIO(self.request.get('csv'))) 
    for row in stringReader: 
     self.response.out.write(row) 

die, wie Sie arbeiten es erwarten.

Bearbeiten Ich nehme an, dass Sie etwas wie eine <textarea/> verwenden, um die CSV-Datei zu sammeln. Wenn Sie einen Anhang hochladen, ist möglicherweise eine andere Handhabung erforderlich (ich bin mit Python GAE und der Verarbeitung von Anhängen nicht vertraut).

+0

Dank! Das hat es gelöst, und deine Erklärung war für mich viel einfacher zu verstehen. –

+0

@August Flanagan Ich glaube nicht, dass die Idee in dem Satz ausgedrückt ** Das Python CSV-Modul arbeitet auf dateiähnliche Objekte, das ist eine Datei oder etwas, das sich wie eine Python-Datei verhält. Daher erwartet csv.reader() ein Dateiobjekt zu erhalten, da es nur der erforderliche Parameter ist. ** ist korrekt. Dokumentation sagt _ "csv.reader (csvfile, dialekt = 'excel', ** fmtparams) Liefert ein Leserobjekt, das über Zeilen in der gegebenen csvfile iteriert. Csvfile kann jedes Objekt sein, das das Iteratorprotokoll unterstützt und jedes eine Zeichenfolge zurückgibt Zeit seine nächste() Methode heißt "_ – eyquem

+0

@AugustFlanagan So ist es klar, dass' 'csv.reader (x)' 'auf ein Objekt' 'x'' funktioniert, das ist nicht unbedingt ein dateiähnliches Objekt, die einzige Voraussetzung ist dass "x" muss ein iterable sein und Strings zurückgeben, wenn es iteriert wird. – eyquem

0

Sie müssen csv_file = self.request.POST.get("csv_import") und nichtcsv_file = self.request.get("csv_import") anrufen.

Die zweite gibt Ihnen nur eine Zeichenfolge, wie Sie in Ihrem ursprünglichen Beitrag erwähnt haben. Aber Zugriff über self.request.POST.get gibt Ihnen ein cgi.FieldStorage Objekt.

Dies bedeutet, dass Sie csv_file.filename aufrufen können, um den Dateinamen des Objekts abzurufen, und csv_file.type, um den Mimetype zu erhalten. Darüber hinaus, wenn Sie auf csv_file.file zugreifen, ist es ein StringO-Objekt (ein schreibgeschütztes Objekt aus der StringIO module), nicht nur eine Zeichenfolge. Wie das in his answer erwähnte ig0774 ermöglicht das StringIO-Modul das Behandeln eines Strings als Datei.

Daher kann der Code einfach sein:

class CSVImport(webapp.RequestHandler): 
    def post(self): 
    csv_file = self.request.POST.get('csv_import') 
    fileReader = csv.reader(csv_file.file) 
    for row in fileReader: 
     # row is now a list containing all the column data in that row 
     self.response.out.write(row) 
Verwandte Themen