Python return filelike object download

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
nho
User
Beiträge: 6
Registriert: Mittwoch 24. September 2014, 08:27

Hallo zusammen!

Ich habe ein filelike object (zipfile.ZipFile), das ich aus einer Pyhton Funktion zurück bekomme und müsste diese nun in einer HTML Seite als downoadlink bereitstellen. Hat jemand eine Idee wie man das machen kann?

Das ganze sieht folgendermaßen aus: Ich habe ein HTML Seite mit einem Formular (action = python funktion), das ich mit JS submitte und nun möchte ich das File, das mir die Python Funktion zurück gibt als downloadlink in die HTML Datei einbinden.

Ich hoffe mir kann wer helfen, bitte danke :)

LG Nina
BlackJack

@nho: Das würde ja bedeuten Du würdest einen Link ausliefern der erst bei der *nächsten* Anfrage das Dateiobkekt ausliefert welches Du in der aktuellen Anfrage im Speicher erstellt hast. So funktioniert das für gewöhnlich nicht. Man würde normalerweise einen Link ausliefern über den das Dateiobjekt bei der Anfrage über diesen Link erst erzeugt und der Inhalt dann auch gleich als Antwort ausgeliefert wird.

Ansonsten müsste man den Inhalt irgendwie persistent machen über die Anfragen hinweg, also letztendlich irgendwo zwischenspeichern. Zum Beispiel auf dem Dateisystem, in einer Datenbank, oder vielleicht auch in einem Cache und in dem Link dann einen Namen, ID, oder Token in den Link einbauen über den man die Datei dann bei der Anfrage wieder identifizieren kann.
nho
User
Beiträge: 6
Registriert: Mittwoch 24. September 2014, 08:27

ok das klingt logisch, was ich bisher habe:

Code: Alles auswählen

sf = tempfile.NamedTemporaryFile("w+b", suffix=".zip", dir = "/mypath")
zf = zipfile.ZipFile(sf, "w", zipfile.ZIP_DEFLATED)
zf.write(...)
downloadlink =  '<a href="zf">your file</a>'
REQUEST.RESPONSE.appendBody(downloadlink)
das funktioniert soweit auch, es wird ein link in der html seite angezeigt, jedoch nicht der link zum file.. Ich verwende Zope!
lg
BlackJack

@nho: Naja Du musst in den Link halt irgendetwas einbauen um die Datei bei einem späteren Aufruf wieder identifizieren zu können, zum Beispiel den Dateinamen oder zumindest einen variablen Teil davon der ausreicht um den Namen zu rekonstruieren.

`NamedTemporaryFile` ist da keine so gute Idee. Ich würde den Dateinamen selber generieren, dann hat man auch selber in der Hand wie sicher das ist gegen Angreifer die Versuchen den Dateinamen von solchen Dateien zu raten. Zum Beispiel auf Basis einer UUID, die man dann auch als Token in den Link einbauen kann.

Auf jeden Fall muss man die Datei am Ende des schreibens schliessen damit auch ganz sicher alle Daten rausgegeschrieben werden, und wenn Du bei `NamedTemporaryFile` bleibst, musst Du dem beim erstellen sagen, dass die Datei beim schliessen *nicht* gelöscht werden soll.
nho
User
Beiträge: 6
Registriert: Mittwoch 24. September 2014, 08:27

ok ich habe der Datei jetzt eine ID zugewiesen bzw. kann man mit zf.filename auch auf den namen des zipfile zugreifen..

das eigentliche Problem ist, dass ich nicht weiß wie ich zwischen Python und JS interagieren kann.. gibt es eine möglichkeit, an der stelle wo ich das Form submitte (und durch die Action die Python Funktion aufgerufen wird), an den Returnwert der Funktion zu gelangen?

LG
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@nho: wenn Du dir Form submittest schickt ja Python eine Antwort zurück. In dieser Antwort mußt Du halt den Link auf die Datei mitschicken.
Wenn Du Dein Skript konkreter beschreibst, kann man vielleicht auch genauer antworten.
nho
User
Beiträge: 6
Registriert: Mittwoch 24. September 2014, 08:27

das ganze sieht folgendermaßen aus:

Ich habe eine html datei mit einem Formular:

Code: Alles auswählen

<form id="initexport" action="path/startExport" method="post">
<input type="hidden" id="dataformat" value="xml" name="dataformat">         
</form>
diese Formular wird mit JS submitted:

Code: Alles auswählen

exportwindow.document.getElementById('initexport').submit();
dadurch wird eine Python Funktion aufgerufen:

Code: Alles auswählen

filetype = REQUEST.get('dataformat')
#erstelle eine Datei, schreibe den Inhalt hinhein und zip
REQUEST.RESPONSE.setHeader('content-type', 'application/zip')
REQUEST.RESPONSE.setHeader('content-disposition', 'attachment;filename="%s.zip"' % 'xmldatei')
REQUEST.RESPONSE.setHeader('content-length', xmlfilelen)
return REQUEST.RESPONSE
dadurch öffnet sich automatisch der filedownload. Ich würde es aber bevorzugen, wenn ein Downloadlink in meine html datei eingebunden wird. Zum Beispiel über einen placeholder im html?
Gibt es da überhaupt eine Möglichkeit?
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@nho: warum der post-Request? Wenn Du einen Link auf einen Export haben willst, warum baust Du den Download-Link nicht direkt in die Seite ein?
nho
User
Beiträge: 6
Registriert: Mittwoch 24. September 2014, 08:27

weil die export Datei erst erstellt werden muss, das geschieht in der Python Funktion. Dort wird ein temporäres File erstellt, mit den Daten befüllt und anschließend soll sie downloadbar sein.

Gibt es eine direkte Methode auf diese Funktion über JS zuzugreifen?
BlackJack

@nho: Das ist keine Antwort auf die Frage. Natürlich muss die Datei vor dem herunterladen erzeugt werden, aber warum wird die nach dem erzeugen dann nicht einfach ausgeliefert anstatt da noch einen Zwischenschritt einzufügen der hauptsächlich Umstände bereitet. Welchen Vorteil bringt das?
nho
User
Beiträge: 6
Registriert: Mittwoch 24. September 2014, 08:27

Weil ich nicht weiß wie das geht :( wie kann ich mit js auf den return Wert der Python Funktion (in dem Fall dann die Datei selber) zugreifen und diese in einen Link verwandeln?
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@nho: Nein, Du erzeugst keinen Link, sondern baust den Link schon in die Seite ein, also statt der Form mit JavaScript einfach das:

Code: Alles auswählen

<a href='path/doExport?dataformat=xml'>XML exportieren</a>
Antworten