Brauche Hilfe: Formular zurück an Flask geben?

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Guten Abend zusammen!

    Ich dreh' mich hier mit meinem Gebastel seit Tagen im Kreis und komme einfach nicht weiter. Könnte mir mal bitte jemand auf die Sprünge helfen?

    Und zwar geht es mir drum, dass ich mir ein Web-Frontend für meine Gartenbewässerung bauen möchte. Da bin ich aber zur Zeit noch meilenweit entfernt von, da ich selbst mit Code-Blöcken aus diversen Tutorials nicht zurecht komme.

    Was ich habe:

    1) app.py Python Skript:

    Die ersten beiden Routen zu index.html und heyhoo.html funktionieren. Beide haben jeweils einen statischen Link auf die andere Seite, und alles funktioniert.

    Die Route zur signup.html bringt mir ein Anmeldeformular. Ab hier klappt es aber nicht. Ich hätte erwartet, dass ich über Klick auf den Button dann in der letzten Route die eingegebenen Daten zurück nach Python bekomme.

    2) signup.html

    3) sript.js JavaScript Datei


    Was mir zum Beispiel auffällt: Wenn ich den Knopf drücke, dann kann ich in WingIDE nicht "live" die print-Aufgabe sehen.

    Aber wenn ich nun ein Skript ändere und der Server sich automatisch neu startet, dann werden plötzlich die print-Ausgaben alle hintereinander ausgeben. dgdgd ist der besagte String aus dem Formular.

    Im Grunde möchte ich "nur" was ganz einfaches:

    1) Daten vom Frontend ans Backend geben

    2) Daten vom Backend ans Frontend geben

    3) Unter "Frontend" verstehe ich eine Webseite, wo hinterher ein paar Knöpfchen drauf sind für die Ventile, sowie eine zweite Seite mit "Einstellungen" etc.

    4) Backend ist für mich die gesamte Logik der Bewässerung, welche in Abhängigkeit von den im Frontend gemachten Einstellungen laufen soll.

    Nur wenn ich bei Google danach suche, dann werde ich erschlagen von unterschiedlichen Meinungen bezüglich dem besten JS-Framework und was weiß ich noch alles.

    Ich hatte mich auf "Bootstrap" und "jQuery" eingeschossen, hauptsächlich weil ich dazu die passenden Widgets gefunden hatte. (Toggle-Button scheint nicht jedes Framework zu haben)

    Würde mich sehr über Hilfe freuen, damit ich mal ein Stück weiter komme.


    Vielen Dank.

    Gruß,

    Marcus

  • Hallo marcuszurhorst ,

    eine kleine Zwischenbemerkung. Es klingt in meinen Augen so, als ob das Projekt zum derzeitigen Zeitpunkt noch eine Nummer zu groß ist. Es gibt funktionierende Systeme (z.B. pimatic), die für einen solchen Einsatz hervorragend geeignet sind. Das kannst Du ja erst einmal verwenden und dich „nebenbei“ an die Programmierung Deiner Lösung machen.

    Bin wieder weg, Gruß, STF

  • Hallo,

    ich muss das STF zustimmen: das Projekt is tzu groß für dich, in so fern das dir die Grundlagen fehlen. Vielleicht nicht unbedingt bei Python, aber von Webprogrammierung an sich.

    Du mischst Datenaustauch per AJAX (also quasi "im Hintergrund") und Datenaustausch per klassischem Request/Response Model. Du mischst beides, dass aber nicht richtig und darum funktioniert es nicht. Grundsätzlich geht das komplett ohne JavaScript / AJAX. und gerade den Login würde ich per klassischem Request/Response bauen.

    Mein Tipp wäre also für's erste:

    Alles JavaScript weg, Bootstrap wenn nur für's Styling (also die CSS-Klassen) nutzen und alles andere klassisch machen.

    BTW, zum Code: das app.run() ist veraltet, Flask-Apps startet man jetzt über das flask-Kommando.

    Gruß, noisefloor

  • Guten Morgen zusammen!

    Klar ist das zu groß für mich. Daher nutze ich ja parallel sogar Gießkanne und Gartenschlauch für die Bewässerung. Ich habe so was noch nie gemacht, und ich habe keinerlei Ausbildung als Programmierer. Dennoch sind eure TIpps nicht gerade motivierend :-/

    Momentan gebe ich irgendwas bei Google ein in der Hoffnung, ein nachvollziehbares Tutorial zu finden. Obiges Anmeldefenster benötige ich nicht für meine Anwendung. Es war nun mal so in dem Tutorial drin, ich hab es kopiert. Würde ich Daten vor- und zurück übergeben können, dann könnte ich mir das analog übertragen.

    Ich hatte verstanden dass ich AJAX/JS schon brauchen würde, damit ich beim Ändern von Einstellungen (z.B. Spinner mit +/- Buttons) nicht bei jedem einzelnen Klick die Seite neu laden müsse. Nun gut, dann suche ich nun mal nach einen klassischen Request/Response Modell.

    Gruß,

    Marcus

  • Prinzipiell würde ich meinen Vorgängern zustimmen, aber das bringt dich ja nicht weiter. ;)

    Es ist eigentlich ganz einfach. Erstmal den AJAX Code entfernen, denn da vermischst du was, wie noisefloor schon sagt. Einen POST-Request sendet der Browser für dich, sofern das Formular korrekt aufgebaut ist. AJAX kannst du in der Tat später für "interaktive Kommunikation mit dem Server" verwenden (klick auf Button o.ä. schickt Request an den Server und macht evtl. etwas mit der Antwort, ohne die Seite neu zu laden). Den <button> würde ich mal in ein <input type=submit"> ändern. Schau auch mal hier: https://www.tutorialspoint.com/flask/flask_se…to_template.htm

    Da ist es gut erklärt und es wird auf das IMHO hier bei weitem nicht nötige Flask WTF verzichtet.

    Statt das result aus dem dortigen Beispiel an das Template weiter zu reichen kannst du mit result['username'] etc. an die Daten kommen.

  • Hallo,

    Programmieren ist halt nicht raten. Wenn dir die Grundlagen fehlen - was ja nicht schlimm ist, keder fängt mal an - kannst du dir halt niemals funktionierenden Code "zusammenkopieren". Weil: du weißt ja nicht bzw. kannst nicht beurteilen, was der Code macht.

    Zitat

    Ich hatte verstanden dass ich AJAX/JS schon brauchen würde, damit ich beim Ändern von Einstellungen (z.B. Spinner mit +/- Buttons) nicht bei jedem einzelnen Klick die Seite neu laden müsse. Nun gut, dann suche ich nun mal nach einen klassischen Request/Response Modell.

    Jein. AJAX macht Sinn, wenn du irgendwas "live" ändern willst / musst und etwas von 0 bis 100 nur in 1er-Schritten ändern kannst / willst. Weil, wie du richtig sagst, du sparst dir dann ein paar Request.

    Aber du kannst das auch später Schritt für Schritt nachrüsten, wenn die Steuerung erst mal läuft.

    Gruß, noisefloor

  • Hallo,

    @marczurhorst: im folgenden ein simples Beispiel für Flask + JavaScript (ohne jQuery) + AJAX. Es gibt zwei Routen: An die eine wird der Wert des Sliders per POST-Request verpackt in Formulardaten geschickt, serverseitig wird einfach nur der Statuscode 200 zurück geliefert.

    An die andere Route werden die Werte der Number-Eingabefelder als JSON geschickt, zurück geliefert wird auch JSON.

    Python:

    HTML + JS:

    Das JS kann man vielleicht noch eleganter machen... JS ist nicht so meine Domäne.

    Gruß, noisefloor

  • Das JS kann man vielleicht noch eleganter machen... JS ist nicht so meine Domäne.

    - const nutzen (statt var). Browser-Support ist super. https://caniuse.com/#feat=const

    - Statt dem absolut hässlichen XMLHttpRequest das neuere (und schönere!!!1!elf) fetch-API nutzen. Browser-Support ist relativ gut (wer nutzt schon Opera Mini oder den IE). https://caniuse.com/#feat=fetch

    Alternativ gibt's ein Polyfill.

    Ansonsten sieht's doch gut aus :)
    Da musste ich schon ganz anderes sehen :shy:

  • Hallo,

    Linus: thx. `fetch()` kannte ich nicht... Hier nochmal die `index.html` mit (hoffentlich) modernerem JavaScript:

    Die Funktionalität hat sich nicht geändert - außer, dass das jetzt wohl nicht mehr mit dem IE funktioniert ;)

    Gruß, noisefloor

  • Besser, aber etwas ungewohnt. Arrow-Functions sind ja jetzt der Trend. 8o

    Ziemlich viele gute Beispiele gibt es ebenfalls auf der MDM-Seite zu praxisnaher Verwendung von fetch.

    Hier mal ein vergleichbares:

    Da sieht man unter anderem, wie man elegant auf einen Statuscode gleich 200 prüfen kann.

    Auch üblich ist das:

    JavaScript
    fetch('/some-json')
    .then(response => response.json())
    .then(json => {
      console.log(json);
    });

    Was wiederum die (legitim) vereinfachte Version von

    Code
    fetch('/some-json')
    .then((response) => {
      return response.json();
    })
    .then((json) => {
      console.log(json);
    });

    ist.

    Ich will aber keinesfalls ausschweifen oder gar deine Arbeit schmälern!

  • Hallo,

    Linus: die MDN Seite hatte ich auch in der Tat zuerst gelesen und mein erster Code mit `fetch` baute darauf auf. Hat auch funktioniert, nur das Error-Handling hat nicht so funktioniert, wie ich mir das vorgestelle habe. Was aber vermutlich an meinen (fehlenden) JS-Skills liegt.

    Der Code im obigen Beispiel basiert auf einer Entwicklerseite von Google. Dieses Promise-Chaining (so heißt das glaube ich...) ist jedenfalls für mich einleuchtender / besser nachvollziehbar.

    @marczurhorst: nicht verwirren lassen - egal, ob du den "alten" XMLHttpRequest nimmst oder das neuere fetch: das Grundprinzip, was da passiert, ist das gleich und auch serverseitg macht das keinen Unterschied, wie du siehst.

    Gruß, noisefloor

  • Hallo zusammen!

    Jetzt ist hier aber Schwung rein gekommen. Vielen Dank.

    Ich habe mir eure Tipps zu Herzen genommen und erst mal mit Grundlagen gespielt. Folgendes läuft hier schon mal:

    1) normale Routen (GET Requests)

    2) POST Requests

    3) Ich kann die Infos aus dem POST nutzen um z.B. meine Objekte zu ändern (sprich, um z.B. die Einstellungen zu ändern)

    4) Ich kriege über GET und POST Infos zurück auf die Webseite

    Was mir nun noch fehlt ist ein automatisches Polling im Hintergrund.

    Plus, viel wichtiger: die alles entscheidende Frage der grundsätzlichen Architektur. :conf:

    Dazu mal eine Frage:

    Meine Steuerung besteht ja aus diversen Teilen (Steuerungslogik, Timer für Automatikbetrieb, Frontend). Die ersten beiden Teile hängen in einem "Programm" zusammen, wobei der Timer als Thread parallel nebenher läuft. Wäre das Frontend nun ein komplett eigenständiges "Programm", oder hänge ich das auch noch mit dem anderen zusammen?

    Ich frage deshalb, da mir nicht 100% klar ist wie die "Verbindung" zwischen den Programmen ausschaut, sobald ich sie voneinander trenne. Und wie ich bei meinem Spielereien bereits bemerkt hatte kann ich ja das Frontend nutzen um meine Objekte zu beeinflussen. Sprich, ich müsste evtl. gar nichts voneinenander trennen und könnte alles im Speicher jonglieren.
     

  • Wenn ich automatisches polling höre schreit das nach WebSockets, speziell mit Flask kann ich socket.io empfehlen. Und dann polling weglassen.

    Dann erzähl mal, was du noch zum Frontend zählst. Den Code, der für dein Flask zuständig ist? Das wäre schon Backend ;)

    Weil das Frontend im Browser läuft kannst du es gar nicht mit dem anderen Code zusammen bringen.

    Ich weiß ja nicht, wie deine verschiedenen Programmteile miteinander kommunizieren. Vielleicht magst du mal ein Schema deiner Architektur zeichnen?

  • Dann erzähl mal, was du noch zum Frontend zählst. Den Code, der für dein Flask zuständig ist? Das wäre schon Backend ;)

    Weil das Frontend im Browser läuft kannst du es gar nicht mit dem anderen Code zusammen bringen.


    Vielen Dank für diesen Satz. Das hat mir gehörig auf die Sprünge geholfen. Ich bin bis dato davon ausgegangen, dass Flask zum Frontend gehört, da dieser Teil von Python ja das HTML ausliefert. Und ich dachte, ich müsste nun 1x ein Flask-Skript schreiben welches unabhängig von meiner Bewässerungslogik sei, aber dennoch mit dieser kommunizieren müsse.

    Ich weiß ja nicht, wie deine verschiedenen Programmteile miteinander kommunizieren. Vielleicht magst du mal ein Schema deiner Architektur zeichnen?

    Ich würde dir gerne ein Schema zeichnen, aber ich scheitere an der Darstellung. Ich versuche es mal in Worten:

    1. Mein Skript stellt mittels Flask ein Webfrontend zur Verfügung.
    2. Der Zustand der Bewässerung (Ventile geöffnet oder geschlossen / Wasserkreis aktiv oder inaktiv / Automatik- oder Handbetrieb, ...) wird aus den Settings raus gelesen vor dem Ausliefern der Seite.
    3. Die Settings liegen in einer INI-Datei und werden beim Starten des Skripts ausgelesen. Ich habe pro Wasserkreis ein Objekt im Speicher liegen mit den zugehörigen Settings und kann von überall darauf zugreifen.
    4. Ich nutze einen parallen Thread, um die Warterei zwischen zwei nächtlichen Bewässerungen zu erledigen ohne das Hauptprogramm zu beinflussen. Dieser Thread wird gestartet wenn ich im Frontend die Automatik anschalte, und er wird beendet wenn ich zurück auf Handbetrieb stelle.
    5. Wenn ich parallel zum nächtlichen Automatikbetrieb auch tagsüber noch manuell bewässere, dann wird die Dauer des geöffneten Ventils auch wieder nachts berücksichtigt.


    Mein größter Fehler war, dass ich OOP als Option angesehen habe. Ich habe mir sehr viel gebastelt mit Funktionen, welche sich kreuz und quer aufrufen. Aber damit komme ich nun ganz klar an Grenzen, und nur durch die Umstellung auf Objekte kann ich auch sinnvoll innerhalb der Flask-Routen darauf zugreifen. Das hat mir die Augen geöffnet und macht einen riesigen Unterschied gerade.


    Nun haben wir aber erst mal Nachwuchs bekommen. Ich sehe (leider) nicht, wo ich da noch Zeit zum Programmieren finden würde ich den nächsten 3-4 Monaten.

    Gruß,

    Marcus

  • Ich würde dir gerne ein Schema zeichnen, aber ich scheitere an der Darstellung. Ich versuche es mal in Worten:

    Ist recht verständlich :thumbup:

    Mein größter Fehler war, dass ich OOP als Option angesehen habe. Ich habe mir sehr viel gebastelt mit Funktionen, welche sich kreuz und quer aufrufen.

    Bei OOP wären das dann aber Klassen und deren Methoden... ;)

    Aber damit komme ich nun ganz klar an Grenzen, und nur durch die Umstellung auf Objekte kann ich auch sinnvoll innerhalb der Flask-Routen darauf zugreifen. Das hat mir die Augen geöffnet und macht einen riesigen Unterschied gerade.

    Was genau verstehst du unter "Objekt"? In Python ist alles ein Objekt, Funktionen, Zahlen, was auch immer. Alles Objekte...

    Nun haben wir aber erst mal Nachwuchs bekommen. Ich sehe (leider) nicht, wo ich da noch Zeit zum Programmieren finden würde ich den nächsten 3-4 Monaten.

    Verständlich. Alles gute euch!

    Ich denke, die in #5 von STF geäußerte Sorge trifft nicht (mehr) zu. Aber, vermutlich der längeren Stille hier geschuldet, ich habe den Überblick über das eigentliche Problem etwas verloren. Wenn du mal Zeit findest: wo hakt es jetzt?

    Edit: Socket.io bzw. flask-socketio kann ich nicht mehr uneingeschränkt empfehlen, ich hatte damit ein Speicherleck, massive Performance-Probleme und Verbindungsabbrüche bei Localhost-Verbindungen! Nach einer Neuimplementierung mit gevent-websocket alles verschwunden. gevent oder eventlet braucht socket.io auch, sonst wird eh polling verwendet.

  • Sorry, hatte mich missverständlich ausgedrückt.

    Ich bin gestartet mit vielen Funktionen, welche in "klassischer" Weise miteinander verknotet habe. So hatte ich vor 25 Jahren mit Pascal die ersten Schritte gemacht in der Schule.

    Was ich natürlich meinte ist, dass ich nun alles auf Klassen und Methoden umstelle, und dann für die Ventile jeweils ein Objekt von dieser Klasse ableite.

    Und diese Ventil-Objekte sind dann über Ihre get/set Methoden überall erreichbar. Ich habe mir ein paar kleine Dummies geschrieben zum Testen. Das funktioniert einwandfrei so ;)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!