Flask Update request wird leer überschrieben

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

Karlirex hat geschrieben: Montag 12. Juli 2021, 18:31 Und wenn ich einmal die __init__ entferne oder durch __repr__ ersetze, dann passiert nämlich nichts bzw. lande ich hier:

Code: Alles auswählen

hplcmethod = HPLCMETHODS(request.form['name'], request.form['eluent'], request.form['column'], request.form['comment'], request.form['temperatur'], request.form['flow'], request.form['retentiontime'], request.form['mitarbeiter'], request.form['gerät'], request.files['inputFile'].read())
In der Fehlermeldung, dass Argumente fehlen, also wird sie ja dort scheinbar gebraucht und aufgerufen.
Du mußt meine Antwort schon auch komplett lesen. Das kann Dir hier auch niemand abnehmen.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

Sirius3 hat geschrieben: Montag 12. Juli 2021, 18:41
Karlirex hat geschrieben: Montag 12. Juli 2021, 18:31 Und wenn ich einmal die __init__ entferne oder durch __repr__ ersetze, dann passiert nämlich nichts bzw. lande ich hier:

Code: Alles auswählen

hplcmethod = HPLCMETHODS(request.form['name'], request.form['eluent'], request.form['column'], request.form['comment'], request.form['temperatur'], request.form['flow'], request.form['retentiontime'], request.form['mitarbeiter'], request.form['gerät'], request.files['inputFile'].read())
In der Fehlermeldung, dass Argumente fehlen, also wird sie ja dort scheinbar gebraucht und aufgerufen.
Du mußt meine Antwort schon auch komplett lesen. Das kann Dir hier auch niemand abnehmen.
Es ändert trotzdem nichts an dem Update-Fehler. Die DB wird da dann weiterhin leer überschrieben, aber eben NUR in dem request.files.....das ergibt für mich eben keinen Sinn.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Aus den Bruchstücken Deines Codes kann man auch nicht wirklich sagen, ob Du alles richtig machst, oder doch noch andere Fehler hast.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

Sirius3 hat geschrieben: Montag 12. Juli 2021, 19:02 Aus den Bruchstücken Deines Codes kann man auch nicht wirklich sagen, ob Du alles richtig machst, oder doch noch andere Fehler hast.

Code: Alles auswählen

from flask import Flask, render_template, request, url_for, redirect, flash, send_file
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import or_
from io import BytesIO

app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///methoden.db'
app.config['SECRET_KEY'] = "random string"

db = SQLAlchemy(app)

class HPLCMETHODS(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(100))
    eluent = db.Column(db.String(500))
    column = db.Column(db.String(500))
    comment = db.Column(db.String(500), nullable = True)
    temperatur = db.Column(db.String(500), nullable = True)
    flow = db.Column(db.String(500), nullable = True)
    mitarbeiter = db.Column(db.String(500), nullable = True)
    retentiontime = db.Column(db.String(500), nullable = True)
    gerät = db.Column(db.String(500), nullable = True)
    data = db.Column(db.LargeBinary)


@app.route("/")
def show_all():
    return render_template('show_all.html', HPLCMETHODS = HPLCMETHODS.query.all())


@app.route('/new', methods=['GET', 'POST'])
def new():
    if request.method == 'POST':
        if not request.form['name'] or not request.form['eluent'] or not request.form['column']:
            flash('Alle Felder beachten.', 'error')
        else:
            hplcmethod = HPLCMETHODS(name = request.form['name'], eluent = request.form['eluent'], column = request.form['column'], comment = request.form['comment'], temperatur = request.form['temperatur'], flow = request.form['flow'], retentiontime= request.form['retentiontime'], mitarbeiter = request.form['mitarbeiter'], gerät = request.form['gerät'], data = request.files['inputFile'].read())#, data)

            db.session.add(hplcmethod)
            db.session.commit()

            flash('Methode erfolgreich hinzugefügt.')
            return redirect(url_for('show_all'))
    return render_template('new.html')


@app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
    method_update = HPLCMETHODS.query.get_or_404(id)
    if request.method == 'POST':
        method_update.name = request.form['name']
        method_update.eluent = request.form['eluent']
        method_update.column = request.form['column']
        method_update.comment = request.form['comment']
        method_update.temperatur = request.form['temperatur']
        method_update.flow = request.form['flow']
        method_update.mitarbeiter = request.form['mitarbeiter']
        method_update.retentiontime = request.form['retentiontime']
        method_update.gerät = request.form['gerät']
        file = request.files['inputFile'].read()
        method_update.data = file
        try:
            db.session.commit()
            flash("Methode bearbeitet")
            return redirect(url_for('show_all'))
        except:
            return "Fehler, versuche es erneut"
    else:
        return render_template('update.html', method_update = method_update)


@app.route('/delete/<int:id>')
def delete(id):
    method_delete = HPLCMETHODS.query.get_or_404(id)
    db.session.delete(method_delete)
    db.session.commit()
    flash('Methode erfolgreich entfernt')
    return redirect(url_for('show_all'))


@app.route('/search', methods=['GET', 'POST'])
def search():
    if request.method == 'POST':
        form = request.form
        search_value = form['search_string']
        search = "%{}%".format(search_value)
        results = HPLCMETHODS.query.filter(or_(HPLCMETHODS.name.like(search), HPLCMETHODS.eluent.like(search), HPLCMETHODS.column.like(search), HPLCMETHODS.comment.like(search), HPLCMETHODS.mitarbeiter.like(search), HPLCMETHODS.gerät.like(search))).all()
        flash(search_value)
        return render_template('show_all.html', HPLCMETHODS = results)
    else:
        return redirect('/')

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['inputFile']
    hplcmethod = HPLCMETHODS(data=file.read())
    db.session.add(hplcmethod)
    db.session.commit()
    return "Saved" + file.filename

@app.route('/download/<int:id>')
def download(id):
    data = HPLCMETHODS.query.filter_by(id=id).first()
    id_string = str(id)
    return send_file(BytesIO(data.data), attachment_filename= id_string, mimetype='image', as_attachment=True)


if __name__ == '__main__':
    db.create_all()
    app.run(debug=True)
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

Hm..soviel zum gesamt Code :D
Naja danke euch trotzdem.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

Habe jetzt mal das ganze (.data) durch ge"printed".
Ergebnis, ist eine Datei drin, erhalte ich den BLOB.
Ist die Datei leer, erhalte ich b' '.

Code: Alles auswählen

@app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
    method_update = HPLCMETHODS.query.get_or_404(id)
    if request.method == 'POST':
        method_update.name = request.form['name']
        method_update.eluent = request.form['eluent']
        method_update.column = request.form['column']
        method_update.comment = request.form['comment']
        method_update.temperatur = request.form['temperatur']
        method_update.flow = request.form['flow']
        method_update.mitarbeiter = request.form['mitarbeiter']
        method_update.retentiontime = request.form['retentiontime']
        method_update.gerät = request.form['gerät']
        method_update.data = request.files['inputFile'].read()
        try:
            db.session.commit()
            flash("Methode bearbeitet")
            return redirect(url_for('show_all'))
        except:
            return "Fehler, versuche es erneut"
    else:
        return render_template('update.html', method_update = method_update)
Leider wird auch keine if-Abfrage vor dem request.files passend aufgelöst, da ich bspw dann nicht mehr ins Updaten komm:

Code: Alles auswählen

        if method_update.data is not 'b''':
            db.session.commit()
            print(method_update.data)
        else:
            method_update.data = request.files['inputFile'].read()
            db.session.commit()
            print('nacher',method_update.data)
Naja ich versuche es weiter.
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Wenn du natürlich den kompletten Datensatz updatest und keine Datei hochladen, ist das Feld natürlich hinterher leer.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@sparrow: Jap, aber es gibt keine sinnvolle if-Abfrage, welche ich nicht schon getestet hab.
zuletzt sowas

Code: Alles auswählen

        method_update.gerät = request.form['gerät']

        if request.files:
            print(request.files['inputFile'])
            print(request.files['inputFile'].read())
            print(len(request.files['inputFile']))
            if (len(request.files['inputFile'].read())) != 0:

            #print(request.files['inputFile'].read())
                print("eine Datei hinzugefügt")
            else:
               # method_update.data = request.files['inputFile'].read()
                print("keine datei hochgeladen")


        try:
und lande trotzdem immer im else egal ob None, 'b'''', oder mit der Länge
Benutzeravatar
__blackjack__
User
Beiträge: 13068
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Karlirex: `read()` liest die Datei. Jedes `read()` danach liefert dann natürlich nichts/leere `bytes`, weil die ja schon gelesen wurden.

Und 'b''' ist eine *Zeichenkette* mit dem Inhalt "b":

Code: Alles auswählen

In [217]: 'b''' == "b"                                                          
Out[217]: True
Das sind keine `bytes`.

Der Test ist aber auch komisch denn der würde bedeuten, dass man keine leere Datei hochladen kann.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@__blackjack__: aber ich kann doch die Bytes sobald die datei übergeben wurde immer auslesen per read() oder etwa nicht? Und dann müsste ich doch auch abfragen können, ob read() etwas enthält oder eben nicht.
Sprich wird eine Datei übergeben wenn das file leer ist, dann kannst du die Datei(Bytes) reinschreiben. Ist das file voll, kannst du dieses mit der neuen Datei überschreiben. Aber ist das file voll und die Datei(Bytes) der neuen request(wie oben in der update_method) leer, dann behalte die Bytes/Datei.
Das ist ja der Punkt, welchen ich an der Stelle (nachdem mir aufgefallen ist, dass ich es vorher immer leer überschreibe) abfragen möchte.
Aus dem Grund hab ich ja dann mit der if für das request.files angefangen.

bei leerer Datei erhalte ich in print(read()) einen Ausdruck b' ', deshalb auch die Idee dies abzufragen. Das lässt er aber durchgehen, egal ob das voll oder leer ist, weshalb ich im else lande.

Zu dem letzten, ist es ja erstmal nur mit print() geschrieben als Test. Da würde ja dann eben bei if ein commit() und beim else eine Beibehaltung der alten Datei reinkommen.
Benutzeravatar
__blackjack__
User
Beiträge: 13068
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Karlirex: Sorry ich verstehe den Beitrag inhaltlich nicht was da nun voll und leer sein soll.

Man kann `read()` nur einmal aufrufen um den Inhalt zu bekommen. Darum ist das unsinnig das im Test zu tun, wenn man den Inhalt danach noch braucht:

Code: Alles auswählen

In [219]: f = open("test.txt", "rb")                                            

In [220]: print(len(f.read()))                                                  
6

In [221]: print(len(f.read()))                                                  
0

In [222]: print(len(f.read()))                                                  
0

In [223]: print(len(f.read()))                                                  
0

In [224]: print(len(f.read()))                                                  
0

In [225]: f.close()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@__blackjack__: okay. also löscht read() nach dem lesen quasi den inhalt? also muss ich mir ne andere speicher/aufrufart suchen? weil ohne das .read() funktionierte es gestern abend mein ich ncht mehr.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Da wird nichts gelöscht. Und die andere Art ist einfach, einmal die Datei zu lesen und sich den Inhalt in einer Variable merken und dann kann man mit der Variable beliebig oft irgendwas machen.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@Sirius3: ich speicher den Inhalt per read() in die Variable hplcmethod.data ganz zu beginn. Ohne das read erhalte ich die Fehlermeldung "bytes object is required, not 'FileStorage'. Ich muss sie aber per .read() in die DB als BLOB setzen, sonst ist diese Datei ja in einem eventuellen zweiten Durchlauf weg, da ich sie nicht local irgendwo als Datei speichern kann. Das geschieht aber in der /new, für die /update kann ich dies dann aber ja nicht mehr speichern per read, wenn es ja angeblich 0 ist.

Habe dann sowas gefunden:

Code: Alles auswählen

            file = request.files['inputFile']
            file.seek(0, 2)
            file_length = file.tell()
            print(file_length)
Für die neue File funktioniert das, die alte File kann ich damit aber nicht mehr abfragen, da diese bereits als BLOB in der DB ist, wo wir beim Ausgangsproblem von oben sind.

Es gibt scheinbar keine Möglichkeit die Datei "non local" hochzuladen, zu vergleichen + bearbeiten und wieder runterzuladen
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Du musst dich wirklich mit den Grundlagen von Python beschäftigen. Insbesondere mit Bytes und file-like-objects.
Sirius3 hat dir doch die Antwort schon gegeben: .read() gibt dir den Inhalt der Datei als bytes. Und wenn du die einmal hast, musst du nicht noch einmal lesen. Du bindest sie einfach an eine Variable.

Ich verstehe auch dein ganzes Vorgehen nicht. Warum sollte es überhaupt einen zweiten Durchlauf geben?
Entweder es gibt ein create oder ein update. Ein "zweiter Durchlauf" macht da keinen Sinn.
Irgendwie ist das, was du da probierst sehr seltsam.

Vielleicht solltest du erst einmal ganz ohne Code erklären, was du eigentlich tun willst.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@sparrow: natürlich gibt es einen zweiten Durchlauf, denn nach dem create ist das update ein zweiter Durchlauf für diese DB Zeile.
Also:
Ich möchte gerne Namen, Eluenten und eben Dateien in einer DB speichern. Diese DB existiert, aber zu dieser wird es keinen lokalen Ordner für Dateien geben. Aus diesem Grund habe ich mich ja für die Bytes-Sache entschieden, da es zumindest was ich so gefunden habe, nur lokale Dateien oder DB Bytes gibt.
Wird der Inhalt in der DB durch create gespeichert enthält diese dann Name, Eluent...und ggf. eine Datei (hier eben als BLOB).
Jetzt möchte ein zweiter PC den Inhalt wie Name, Eluent...bearbeiten (dieser hat die ursprüngliche Datei nicht mehr), dann soll die usprüngliche Datei (also das BLOB) erhalten bleiben.
Danach möchte ich oder ein dritter PC diese Methode nochmal bearbeiten, weil es eine neue "bessere" Datei gibt, also soll die bisherige Datei durch die neue überschrieben werden.
Anschließend lädt irgendeiner der PCs die Datei dann herunter.
Fertig.

Hinweis: Beim Bearbeiten, so wie es ganz am Anfang programmiert ist, bleiben die Punkte Name, Eluent...mit den Werten aus create bestehen (mit dem gleichen Code), deshalb auch der erste Ansatz da einfach das request.files() anzuhängen.

Ich hoffe, ihr versteht nun was da genau passieren soll und das es eben schon für die ersten Punkte passiert.
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Natürlich gibt es keinen zweiten Durchlauf. Ein zweiter Durchlauf suggeriert, dass das nacheinander passiert.
Es gibt ein Create und davon völlig unabhängig ein Update.

Du musst dich mit der Systematik beschäftigen. Und ich bin mir ziemlich sicher, dass es in der Flask-Dokumentation ein ausführliches Beispiel dafür gibt, wie Dateiuploads gehandhabt werden. Ein erster Versuch an google ergab diesen Treffer.

Wenn jemand eine neue Datei uploaded, dann musst du das Feld updaten. Weder musst du das immer tun, noch musst du dafür die alte Datei aus der Datenbank lesen und noch einmal übertragen. Neue Datei -> Update des Feldes. Keine neue Datei -> Kein Update des Feldes.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@sparrow: NOCHMAL die Doku bringt mir NICHTS, da ich aus einer DATENBANK ohne LOKALEN FILEORDNER arbeite und deshalb ich mit den BYTES arbeiten MUSS.

Den Upload zu prüfen habe ich ja versucht mit dem if request.files! Das läuft er aber jedes Mal trotzdem durch.
Beispielsweise habe ich mir vor dem if == POST eine Überprüfung gesetzt.

Code: Alles auswählen

@app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
    method_update = HPLCMETHODS.query.get_or_404(id)
    data = HPLCMETHODS.query.filter_by(id=id).first()
    old_file = data.data
    print(old_file)
    if request.method == 'POST':
        method_update.name = request.form['name']
        method_update.eluent = request.form['eluent']
        method_update.column = request.form['column']
        method_update.comment = request.form['comment']
        method_update.temperatur = request.form['temperatur']
        method_update.flow = request.form['flow']
        method_update.mitarbeiter = request.form['mitarbeiter']
        method_update.retentiontime = request.form['retentiontime']
        method_update.gerät = request.form['gerät']
Diese printed einmal beim auf Update klicken, was ja richtig ist. Submite ich, printed diese allerdings nochmal.
Ich kann also garnichts logisch abfragen, da sie sich vorher und nachher mit den Werten überschreibt und oben nochmal läuft.

und in meiner update-html:

Code: Alles auswählen

 <form action = "{{ request.path }}" method = "post" enctype="multipart/form-data">
          <table>
              <thead>
                <th><label for = "name">Name</label></th>
                <th><label for = "eluent">Eluent</label></th>
                <th><label for = "column">Säule</label></th>
                <th><label for = "comment">Kommentar</label></th>
                <th><label for = "temperatur">Temperatur [°C]</label></th>
                <th><label for = "flow">Fluss [ml/min]</label></th>
                <th><label for = "retentiontime">Retentionszeit [min]</label></th>
                <th><label for = "mitarbeiter">Mitarbeiter</label></th>
                <th><label for = "gerät">Gerätename</label></th>
                <th><label for = "data">Datei</label></th>
              </thead>

              <tbody>
                <td><input type = "text" name = "name" placeholder = "Name" value = "{{ method_update.name }}" /></td>
                <td><input type = "text" name = "eluent" placeholder = "Eluent" value = "{{ method_update.eluent }}" /></td>
                <td><input type = "text" name = "column" placeholder = "Säule" value = "{{ method_update.column }}" /></td>
                <td><input type = "text" name = "comment" placeholder = "Kommentar" value = "{{ method_update.comment }}" /></td>
                <td><input type = "text" name = "temperatur" placeholder = "Temperatur" value = "{{ method_update.temperatur }}" /></td>
                <td><input type = "text" name = "flow" placeholder = "Fluss" value = "{{ method_update.flow }}" /></td>
                <td><input type = "text" name = "retentiontime" placeholder = "Retentionszeit" value = "{{ method_update.retentiontime }}" /></td>
                <td><input type = "text" name = "mitarbeiter" placeholder = "Mitarbeiter" value = "{{ method_update.mitarbeiter }}" /></td>
                <td><input type = "text" name = "gerät" placeholder = "Gerätename" value = "{{ method_update.gerät }}" /></td>
                <td>
                        <input type="file" name="inputFile" value = "{{ method_update.data }}" />
                </td>
                <td><input type = "submit" value = "Bearbeiten" /></td>
Bleiben damit eben die text-inputs stehen nur die File eben nicht, auch bei dem einfachen Post, wo ich alles überschreibe, weil die eben da drin stehen bleiben.
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Ich bin beeindruckt, mit welcher Geschwindigkeit du den Inhalt des Links gelesen hast. Sicher so schnell, dass du überlesen hast, wie dort beschrieben wird, wie man erkennt, ob der User eine Datei ausgewählt hat. 8)
Denn dem Request und dem Upload ist egal, ob die Datei in eine Datei oder in eine Datebank geht.
Dir ist schon klar, dass das zwei verschiedene Dinge sind? Und dass dein Problem an der Seite hängt, wo du Sachen hoch lädst und nicht an der wie du speicherst? Auch wenn du in eine Datei schreiben würdest, hättest du das selbe Problem.
Du musst herausfinden, ob der Anwender eine Datei hochlädt oder nicht.
Das habe ich nun ja auch in meinem vorherigen Post geschrieben. Wenn du denkst, dass das anders gehen muss: Viel Glück.

Um das Lesen und Lernen wirst du nicht herum kommen. Das nimmt dir niemand ab.
Karlirex
User
Beiträge: 126
Registriert: Dienstag 18. August 2020, 18:27

@sparrow: ich gebe zu ich hab das überlesen, ich konnte für mich nichts mit dem .filename nichts anfangen, dachte ich will ja nicht den filename speichern.
Ich bedanke mich für deine Geduld und werde mich etwas mehr in Dokus lesen bzw. teile dieser ."Befehle" öfter googlen, denn das hätte hier schon wahrscheinlich früher gereicht, da ich über das .filename nicht gerade erst gestolpert bin.

Vielen Dank an eure Hilfe und auch für die Geduld, macnhmal ein kleiner *Holzkopf*

Grüße
Karlirex
Antworten