Download von Dateien

Django, Flask, Bottle, WSGI, CGI…
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast offensichtlich den Inhalt Deines Dataframes als Pfad benutzt. Ohne Code läßt sich dazu nichts sagen, aber wenn ich raten müßte, hast Du nicht nur StringIO sondern auch BytesIO entfernt, was dann eins zu viel war. send_file erwartet als erstes Argument einen Dateinamen oder eben ein file-like Objekt.
Sternenregen
User
Beiträge: 39
Registriert: Mittwoch 13. Januar 2021, 16:17

Das ist der Code.

Code: Alles auswählen

@app.route('/saveResults', methods=['GET', 'POST'])
def save_results():

    dicttest = {"test1": 123, "test2": 123}
    df = pd.DataFrame.from_dict(dicttest, orient='index')
    csvfile = df.to_csv()
    buffered_str = io.StringIO(csvfile)
    bufferd_bytes = io.BytesIO(buffered_str.read().encode("utf-8"))

    return send_file(bufferd_bytes,
              mimetype="text/csv",
              download_name='test.csv',
              as_attachment=True)

Code: Alles auswählen

$(document).ready(function(){
    $('#save-result').click(function(){
        console.log("asdf");
        $.ajax({
            type: 'POST',
            url: '/saveResults',
            success: function(data){
                console.log("successfasdf");
            }
        });
    });
});
Es wird sogar in den Success gesprungen. Aber nichts passiert. Nichts wo gedownloaded wird. Aber ja, ich stimme dir zu. Das ist ein grundlegendes Problem.
Der Mac kriegt es jedenfalls hin.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist wieder ein anderer Code, als der, der die Fehlermeldung produziert hat.
Dort stand nämlich

Code: Alles auswählen

return send_file(csv_file,
Korrekt wäre:

Code: Alles auswählen

@app.route('/saveResults', methods=['GET', 'POST'])
def save_results():
    dicttest = {"test1": 123, "test2": 123}
    df = pd.DataFrame.from_dict(dicttest, orient='index')
    buffered_bytes = io.BytesIO()
    df.to_csv(buffered_bytes)
    return send_file(buffered_bytes,
              mimetype="text/csv",
              download_name='test.csv',
              as_attachment=True)
Und was erwartest Du? Natürlich kommt da kein Download. Du machst einen AJAX-Call, dessen Ergebnis von Javascript im Browser verarbeitet wird. Du machst aber mit `data` nichts.
Sternenregen
User
Beiträge: 39
Registriert: Mittwoch 13. Januar 2021, 16:17

Vielen Dank. Darin lag der Denkfehler. Ein dummer Fehler.

Vielen Dank an alle Beteiligten.
Sternenregen
User
Beiträge: 39
Registriert: Mittwoch 13. Januar 2021, 16:17

__blackjack__ hat geschrieben: Sonntag 5. September 2021, 20:48 @Sternenregen: Vielleicht dauert es einfach nur sehr lange und/oder der Speicher reicht nicht aus. Das Vorgehen ist nicht wirklich speicherschonend. Alleine der Code den wir sehen hat das ganze Ergebnis als DataFrame und als Zeichenkette und als Bytes-Objekt gleichzeitig im Speicher. Und einen grossen DataFrame dynamisch aufzubauen ist auch nicht so toll, und wenn da auch alles an Namen gebunden wird, gibt es da das komplette Ergebnis vielleicht *noch mal* komplett im Speicher.

Ich würde mir mal den Speicherverbrauch auf dem Produktivsystem anschauen.
Ok. Was könnte man da dagegen tun?

Jetzt wo es vermeintlich funktioniert, bekomme ich wieder den Rekursionsfehler: Aber jetzt kann ich ihn auch posten:

Code: Alles auswählen

ERROR:app:Exception on /downloadResult [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/meineApp/app.py", line 239, in get_result
    buffered_csv = get_result()
  File "/meineApp/app.py", line 239, in get_result
    buffered_csv = get_result()
  File "/meineApp/app.py", line 239, in get_result
    buffered_csv = get_result()
  [Previous line repeated 985 more times]
RecursionError: maximum recursion depth exceeded
Wie könnte man das ganze effizienter gestalten?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Offensichtlich tritt der Fehler in einem Stück Code auf, den du uns nach wie vor verheimlichst.
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sternenregen: Jetzt kennen wir den Traceback, aber den Code dazu nicht. Die Zeile da haben wir bis jetzt noch in keinem Code-Schnippsel gesehen. Ausser zu sagen: Ruf da halt nicht endlos rekursiv auf, kann man da also nicht viel zu sagen.

Bezüglich der Speichereffizienz: Binde halt nicht jedes Zwischenergebnis an einen Namen, damit nicht jedes Zwischenergebnis im Speicher existieren muss solange die Namen existieren. Und ich würde auch schauen ob man da wirklich Pandas verwenden muss. Und wenn es wirklich viele Daten sind, ob man das Ergebnis nicht auch streamen kann, statt es im Speicher komplett zu erzeugen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sternenregen
User
Beiträge: 39
Registriert: Mittwoch 13. Januar 2021, 16:17

Asche auf mein Haupt. Zugegeben das lag jetzt auch an mir, weil ich den Code verändert hier für das Forum abgetippt habe.

Der Fehler lag daran, dass die Methode die das File zurückliefert, den gleichen Namen wie die Funktion der Route hatte. Daher der Rekursionsfehler.

Nicht gerade eine Sternstunde von mir. :(
Antworten