Flask render_template funktioniert nicht

Django, Flask, Bottle, WSGI, CGI…
Antworten
ChristophS
User
Beiträge: 52
Registriert: Montag 7. August 2017, 12:52

Hallo Zusammen
Ich nerve Euch mal wieder. Ich versuche seit Tagen eine Lösung zu finden.

In Python mache ich folgendes:

Code: Alles auswählen

@app.route('/login', methods=['POST'])
def login():    
    data = request.data    
    data = data.decode('ascii').split(',')

# Hier suche ich in Sqlite nach Daten. Das Ergebnis ist in user_data. Funktioniert einwandfrei

    if user_data != []:    #Wenn Erfolg dann das Template rendern ...
        return render_template('/blank.html')
    else:  #sonst meinem javascript melden.
        return []
Das javascript sieht so aus:

Code: Alles auswählen

async function loginUser(userData) {
  event.preventDefault();
  const response = await fetch(
    "/login", {
      "method": "POST",
      "body": userData,
    }
  );

  if(response.ok) {
    const data = await response.json();
    if (data.length == 0) {
      alert('Passwort und/oder Username stimmt nicht!');
  }
}

Meine Vermutung lag darin, dass die Funktion loginUser auf etwas wartet, nicht passiert. Darum habe ich die Funktion ergänzt und es sieht jetzt so aus:

Code: Alles auswählen

async function loginUser(userData) {
  event.preventDefault();
  const response = await fetch(
    "/login", {
      "method": "POST",
      "body": userData,
    }
  );

  if(response.ok) {
    const data = await response.json();
    if (data.length == 0) {
      alert('Passwort und/oder Username stimmt nicht!');
    }else{
        alert('Login OK');
        $.post("/main/{'userData': 'test'}")
    }
  }
}
In Python dann so:

Code: Alles auswählen

@app.route('/main/<test>', methods=['POST'])
def main(test):
    return render_template('blank.html')
Die Variable 'test' kommt an (habe ich mit print() kontrolliert, aber das Template wird nicht grendert.
Eine Fehlermeldung erhalte ich weder vom Browser noch von Python.

Lieber Gruss

Christoph
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

Was ist userData? Normalerweise schickt man mit Post entweder als multipart/form-data oder Json oder ähnliches, aber man erfindet kein eigenes Format, das zudem Probleme mit Komata und Umlauten hat.
blank.html sieht nicht so aus, als ob das json generieren würde, wäre auch sehr umständlich. Ein Fehlerhafter User würde man mit einem HTTP-Errorcode melden und nicht durch eine leere Liste.
Dein nächster Versuch ist auch seltsam. Man schickt kein seltsam codierten Wörterbücher als GET-Request. Seit gut 15 Jahren sind alle Browser so Standardkonform, dass etwas wie jQuery nur unnötiger Balast ist. Mit dem Ergebnis des POST-Requests machst Du dann auch nichts.
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

was hier ja grundsätzlich schon mal extrem schräg ist, dass die per fetch-API angefragten Daten entweder ein HTML Dokument sind oder eine leere Liste, obwohl JSON erwartet wird. Wenn du mit Flask Daten auf Python als JSON schicken willst, nimmst du `jsonify`, was Flask an Bord hat und kein `render_template`.

Bei so Problemen hilft es auch immer, den Debugger der Entwicklertools des Browser anzuwerfen, da kann man dann i.d.R. Fehlermeldungen des JavaScript nachvollziehen und sieht auch welche Daten gesendet und Empfangen wurden.

Bzgl. der von @Sirius3 bereits angesprochenen Fehler bei nicht-erfolgreicher Authentifizierung: dann sendet man entweder einen 401 Fehler oder 403 Fehler. Je nach dem, woran die Authentifizierung scheitert.

Gruß, noisefloor
ChristophS
User
Beiträge: 52
Registriert: Montag 7. August 2017, 12:52

Die Entwicklertools habe ich eingeschaltet.

Danke für den Hinweis mit den HTML Fehler. Das macht den Code nicht nur einfacher sondern besser Lesbar. Wie gesagt ich bin Anfänger.

Code: Alles auswählen

async function loginUser(userData) {
  event.preventDefault();
    const response = await fetch(
      "/login", {
      "method": "POST",
      "body": userData,
    }
  );

  if(response.ok) {
      
/* hier Möchte ich die aktuelle Seite schliessen und eine neue Seite rendern und habe das so Versucht:    
      fetch(
        "/main", {
      }
    );
    die Browser Konsole zeigt keinen Fehler;
    die Terminal Konsole zeigt: 
    127.0.0.1 - - [14/Feb/2025 12:14:24] "GET /main HTTP/1.1" 200 -
   
*/
      
    }else{
      alert('Das Passwort oder der Benutzer stimmt nicht')
  }
}

Code: Alles auswählen

@app.route('/main')
def main():
    return render_template('blanc_page.html')
Die blanc_page.html hat nur den Inhalt:
<h1>Leere Seite</h1>
Lieber Gruss

Christoph
ChristophS
User
Beiträge: 52
Registriert: Montag 7. August 2017, 12:52

@Sirius
userData ist eine Liste mit zwei Werten (Benutzer, Passwort) die ich in Python überprüfe.
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das funktioniert so nicht, da sind auch mehrere größere Verständnisfehler drin.

Also: wenn du mittels fetch-API Daten, z.B. in Form von JSON, abholst, passiert damit im Client erst mal gar nichts, außer dass die im JavaScript an einen Namen gebunden sind. Du musst dich selber darum kümmern, gezielt einzelne Daten aus den Gesamtdaten zu ziehen und die dann mittels JavaScript die dargestellte Webseite an den gewünschten Stellen zu aktualisieren / manipulieren. Also bei

Code: Alles auswählen

fetch(
        "/main", {
      }
    );
passiert nichts, außer das versucht wird, von der Route `main` Daten zu ziehen.

Aber: wenn du "hier Möchte ich die aktuelle Seite schliessen und eine neue Seite rendern und habe das so Versucht: " haben willst, dann ist der Ansatz via fetch sowie suboptimal, dass kann man ganz normal über einen Request-Response Zyklus machen, ohne JavaScript. Das passende Beispiel findest du sogar im Flask Quickstart Guide: https://flask.palletsprojects.com/en/st ... est-object

Gruß, noisefloor
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

@ChristophS: userData ist offensichtlich keine Liste mit zwei Werten, denn sonst würdest Du auf Python-Seite nicht per split darauf losgehen, sondern ganz normal json parsen.
Wenn du nach einem erfolgreichen Login auf eine Seite weiterleiten willst, dann setze doch einfach die Location:

Code: Alles auswählen

async function loginUser(username, password) {
   const response = await fetch("/login", {
      "method": "POST",
      "body": JSON.stringify({ username, password }),
   });

   if(response.ok) {
      location.href = '/blank.html'
   }else{
      alert('Das Passwort oder der Benutzer stimmt nicht')
   }
}
Was ist eigentlich Dein Ziel? Bei einer typischen SinglePageApplication ändert sich die Location nie.
ChristophS
User
Beiträge: 52
Registriert: Montag 7. August 2017, 12:52

Herzlichen Dank.

Mein Ziel:
Ich habe verschiedene Apps in Python. Herunter gebrochen sind es im wesentlichen interaktive Formulare mit Unterformularen die gleichzeitig angezeigt werden. Jetzt will ich die Apps aber nicht nur einer Person zur Verfügung stellen, sondern einer Gruppe von Personen; darum Flask.
Mein Ansatz war für jede App ein eigenes Template zu erstellen, das in einem Hauptmenü angewählt werden kann.

Ich denke, der entscheidende Hinweis ist, dass sich normalerweise bei einer SinglePageApplication die Location nie ändert. Vermutlich versuchte ich etwas was so nicht Vorgesehen ist (href funktioniert auch nicht, die URL wird nicht gefunden) und mein Ansatz war schlicht falsch.

Im Prinzip ist das kein Problem, da eine SinglePage mit JavaScript bearbeitet bzw. gestaltet werden kann. Ist einfach ein anderer Weg.

Danke nochmals Euch beiden für die Hilfe die mir sehr geholfen hat.

Lieber Gruss

Christoph
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Danke für die Erklärung. Aber: das macht alles irgendwie keinen Sinn oder du benutzt einfach eine Nomenklatur, die sonst keiner so nutzt. Unter anderem:
Mein Ansatz war für jede App ein eigenes Template zu erstellen, das in einem Hauptmenü angewählt werden kann.
"App" im Kontext von Flask ist eine in sich geschlossene Applikation, die einen bestimmten Umfang an Funktionalität, Aufrufbar über Routen, beinhaltet. Wie viele Templates darin unterbringst hängt von dir bzw. den gegeben Notwendigkeiten ab. Eine App ist im Flask Kontext das, was du mit `app=Flask(__name__)` instanzierst. Du kannst auch mehrere Flask Apps über eine Applikationsserver ausliefern, siehe https://flask.palletsprojects.com/en/st ... pdispatch/.

Wenn du wirklich für jedes Template eine App im Sinne von Flask App erstellst, hast du ziemlich sicher beim Projektentwurf einen konzeptionellen Fehler drin.

Hat aber mit der Ausgangsfrage "render_template funktioniert nicht" alles nix mehr zu tun.

Gruß, noisefloor
Antworten