Fehlersuche Flask, mit Vue.js

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

Du benutzt ja die Liste `gases` gar nicht, sondern jedes Dropdown ist mit der selben Variablen `gas_name` verknüpft.
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Ach, was soll ich dazu auch sagen, außer vielen Dank für den Hinweis.
Jetzt funktioniert es 🙂 :

Code: Alles auswählen

<html>
<head>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">

  <h2>Gasmischung erstellen</h2>
  <li v-for="gas in gases" :key="gas_name">
    <select v-model="gas[gas_name]">
      <option disabled value="">Bitte auswählen</option>
      <option v-for="name in validGases" :key="name">
        {{name}} </option>
    </select>
    <input v-model="gas[percent]">%
  </li>
  <button @click="add_gas">+</button>

</div>

<script>
  const { createApp, ref } = Vue

  createApp({
    setup() {
      const gases = ref([{gas_name: undefined, percent: undefined}])
      const gas_name = ref("")
      const percent = ref(0)

      function add_gas() {
        gases.value.push({gas_name: gas_name.value, percent: percent.value})
      }

      validGases = [
        "H2",
        "CO2",
        "CO"
      ]

      return {
        add_gas, 
        gas_name, 
        percent, 
        gases, 
        validGases
      }
    }
  }).mount('#app')
</script>
</body>
</html>
Ist die Vorgehensweise eigentlich okay so oder gibt es etwas geschickteres?

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Abend zusammen,

habe es geschafft, dass die Seite alle Eingabefelder ink. der Gasmischung in JavaScript validiert. Hat mich nur 5 Nervenzusammenbrüche gekostet und aus den Haaren auf dem Schreibtisch, kann man zumindest einen kleinen Besen machen. :)

Nun müssen die Daten Richtung Flask-App geschickt werden. In meinem Tutorial wird dafür `axios` importiert. Wenn ich das hier auch mache, dann funktioniert das ganze Skript nicht mehr. Gibt es eigentlich irgendwas, das etwas mehr an Fehlerbehandlung bietet, als die Browser-Console?
Im Internet habe ich noch etwas von `$.ajax` gelesen und noch von 'fetch'.
Letzteres habe ich mal versucht, hatte damit auch Erfolg:

Code: Alles auswählen

<html>
<head>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
  <h2>Eingabe</h2>
  <input v-model="user_entry">
  <button @click="to_python">Send</button>
</div>

<script>
  const { createApp, ref } = Vue

  createApp({
    setup() {
      const user_entry = ref("")

      function to_python() {
        fetch('http://localhost:5000/index', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({"eingabe": user_entry.value})
        })
      }

      return {
        to_python, 
        user_entry, 
      }
    }
  }).mount('#app')
</script>
</body>
</html>
Gibt es irgendwelche Vor- und Nachteile? Mit was soll ich sinnvollerweise weiter machen? Ich muss ja nachher auch wieder die berechneten Daten empfangen. Nur weil ich das mit `fetch` im Testprogramm hinbekommen habe, will ich das nicht zwangsläufig verwenden, falls es Gründe gibt, die dagegen sprechen?

Vielen Dank und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da fehlt noch so ein bisschen ``await`` und Behandlung der Antwort, also Fehlerbehandlung. Es sei denn das soll wirklich „fire & forget“ sein, und es ist egal falls da irgend etwas schief läuft.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen und danke für den Hinweis.

Nee, das soll ordentlich werden, mit allem was dazu gehört. Die Frage für mich ist nur, wie?
`await` kann ich im Zusammenhang mit JavaScript mal googln.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Das ist im Grunde wie ``await`` in Python. Und `fetch()` liefert ein Promise für ein `Response`-Objekt, das so ähnlich ist wie in Python `requests.Response`. Man kann da beispielsweise schauen ob das `ok`-Attribut ``true`` ist.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für die Antwort und sorry für meine späte Rückmeldung. Musste das Projekt etwas hinten anstellen.
Für `await` und `async` gibt es viele Beispiele. Das Senden funktioniert weiterhin, ich frage mich nur, was kann denn da schief gehen und wie reagiere ich da sinnvoll darauf?
Ich hab die *.html-Datei mal so erweitert:

Code: Alles auswählen

<html>
<head>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
  <h2>Eingabe</h2>
  <input v-model="user_entry">
  <button @click="to_python">Send</button>
</div>

<script>
  const { createApp, ref } = Vue

  createApp({
    setup() {
      const user_entry = ref("")

      async function to_python() {
        const response = await fetch('http://localhost:5000/index', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({"eingabe": user_entry.value})
        })
        if (!response.ok) {
          console.log("Irgendwas ging schief, aber was?");
        }
      }

      return {
        to_python, 
        user_entry, 
      }
    }
  }).mount('#app')
</script>
</body>
</html>
Fehlt da noch was oder wie kann ich Fehler simulieren, die auftreten können, damit ich eine Fehlerbehandlung einbauen kann?

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: 404 wenn die Seite nicht gefunden wird, irgend ein 500er wenn das Programm was die Daten entgegen nimmt in eine Ausnahme läuft, … die üblichen Sachen halt.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen und Danke,

gestern Abend habe ich in der Python-Funktion `index` einfach mal das `return` weggelassen, so dass folgende Aufnahme auftritt:

Code: Alles auswählen

TypeError: The view function for 'App:index' did not return a valid response. The function either returned None or ended without a return statement.
127.0.0.1 - - [10/May/2024 09:02:02] "POST /index HTTP/1.1" 500 -

Hätte dann jetzt in der Browser-Console nicht mein Text "Irgendwas ging schief, aber was?" auftauchen müssen?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
sparrow
User
Beiträge: 4227
Registriert: Freitag 17. April 2009, 10:28

Was würdest du denn in Python tun? Schauen was response ob dem Fall ist. Und wie deine Bedingung darauf reagiert.
Same here.
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für die Antwort. Dann werde ich für verschiedene Fälle, passende Meldungen vorbereiten.

Mein vorheriger Beitrag war Quatsch, natürlich wird in der Browser-Console meine Meldung angezeigt. Ich hatte noch den Code geändert und nicht vollständig auf den hier geposteten zurück gesetzt. Da war meine Unachtsamkeit schuld.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Abend,

ich verstehe schon wieder etwas nicht und bitte euch, mir zu helfen.
Ich habe `Data.json` erstellt, mit folgendem Beispielinhalt:

Code: Alles auswählen

[
  {
    "name": "Typ A",
    "size": 100,
  },
  {
    "name": "Typ B",
    "size": 200,
  },
]
Eine Python-Flask-Datei mit der ich meine einzelnen Schritte durchspiele:

Code: Alles auswählen

#!/usr/bin/env python
from json import loads
from pathlib import Path

from flask import Flask, jsonify
from flask_classful import FlaskView, request, route
from flask_cors import CORS

DATA_FILE = Path(__file__).parent / "TechnicalData/Data.json"


class App(FlaskView):
    def __init__(self, cooler_data):
        self.cooler_data = cooler_data

    @route("/get_data", methods=["GET"])
    def get_data(self):
        if request.method == "GET":
            return self.cooler_data


def main():
    app = Flask(__name__)
    app.config.from_object(__name__)
    CORS(app, resources={r"/*": {"origins": "*"}})
    App.register(
        app, route_base="/", init_argument=loads(DATA_FILE.read_bytes())
    )
    app.run()


if __name__ == "__main__":
    main()
Und diese *.html - Datei:

Code: Alles auswählen

<html>
<head>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
</div>

<script>
  const { createApp, ref } = Vue

  createApp({
    setup() {
      async function getTypes(){
        const response = await fetch('http://localhost:5000/get_data');
        const data = await response.json();
        console.log(data)
        return data;
      }
      Types = getTypes();
      console.log(Types);

      return {
      }
    }
  }).mount('#app')
</script>
</body>
</html>
Ich möchte "nachher" den Wert von `name` aus meiner `Data.json` in ein Dropdown-Menü anzeigen.
Als ich mir die ankommenden Daten in der Funktion `getTypes` angeschaut habe, habe ich mich eigentlich gefreut, weil das so aussah:

Code: Alles auswählen

Array(8) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…} ]
Super, da kann ich sicherlich einfach durch iterieren.

Also habe ich das Arry zurückgegeben und an `Types` gebunden. Doch `Types` ist plötzlich kein Array mehr. Zumindest zeigt mir die Console ein `Promise` - Objekt an:

Code: Alles auswählen

Promise { <state>: "pending" }
​
<state>: "fulfilled"
​
<value>: Array(8) [ {…}, {…}, {…}, … ]
​
<prototype>: Promise.prototype { … }
Ich sehe dass da das Array drin ist. Aber erst würde ich gerne verstehen, wieso das so ist?
Wie komme ich jetzt an das Array?
Konnte eigentlich nur raten und weder `Types.value` oder `Types['value']` liefert etwas bzw. es liefert beides mal ein "undefined".

Vielen Dank und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Deine `getTypes()`-Funktion ist ``async``. Also hast Du ein `Promise` als Rückgabewert. Wenn Du auf das Ergebnis vom Promise warten möchtest, fehlt da ein ``await``.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen,

danke für den Hinweis. Ich kann `await` nur in einer `async` - Funktion verwenden (habe ich zumindest so gelesen), dann habe ich eigentlich nur noch eine Stelle, an der ein `await` Platz hätte:

Code: Alles auswählen

async function getTypes(){
        const response = await fetch('http://localhost:5000/get_data');
        const data = await response.json();
        console.log(data)
        return await data;
      }
Aber das sieht falsch aus, weil ich warte ja schon auf `data`? Habs natürlich getestet, bringt aber keine Veränderung.
Ich bin auch davon ausgegangen, dass ich mit den `await` die ich schon drin habe, auf das Ergebnis warte.

Damit ich da von Anfang an keinen Denkfehler habe, ich habe das so verstanden, dass `await` die Funktion so lange pausiert, bis da ein Rückgabewert kommt oder eventuell ein Timeout.
Deine Aussage, dass da immer ein `Promise` - Objekt zurückgegeben wird, habe ich jetzt auch hier gefunden:
https://developer.mozilla.org/en-US/doc ... c_function

Aber entweder lese ich zu schlampig, verstehe es nicht oder finde keinen Weg, wie ich den Wert zurückgeben kann.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
sparrow
User
Beiträge: 4227
Registriert: Freitag 17. April 2009, 10:28

Wenn du 'await' nur in 'async'-Funktionen verwenden kannst dann musst du nichts an getTypes ändern sondern setup async machen, würde ich sagen.
Sirius3
User
Beiträge: 17788
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dennis89: async ist wie unter Python kooperativ, das heißt, wenn eine Async-Funktion wartet, kann die andere, deren Ergebnis da ist, weitermachen. Dazu müssen aber alle Funktionen bis hoch zu einer "Main"-Funktion asynchron arbeiten. Bei Python ist das explizit über das Aufrufen vom Eventloop gelöst, in Javascript, das eh komplett Event-basiert arbeitet, ist der Eventloop versteckt.

Die meiner Meinung nach verständlichste Lösung ist das Füllen der Variablen außerhalb von setup über das onMounted-Event

Code: Alles auswählen

  const { createApp, ref, onMounted } = Vue

  createApp({
    setup() {
      types = ref([])

      onMounted(async () => {
        const response = await fetch('/get_data');
        types.value = await response.json();
      })

      return {
          types
      }
    }
  }).mount('#app')
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für eure Antworten und Erklärungen.

Die Lösung funktioniert.

Ich verstehe das `onMounted` - Event und das macht ja auf jeden Fall Sinn, weil ich die Daten von Anfang an benötige.
Eigentlich hätte ich das so auch in meiner Funktion machen können? Unschön ist halt der Funktionsaufruf, der dann einfach irgendwo steht.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 17788
Registriert: Sonntag 21. Oktober 2012, 17:20

Nein, Du hast die Daten nicht von Anfang an, weil sie asynchron nachgeladen werden.
Und Du brauchst diesen "Funktionsaufruf", weil Du ja die Daten asynchron laden mußt.
Eventbasierte und Nebenläufige Programmierung sind halt schwierige Themen, um die man aber nicht herum kommt, sobald man eine Server/Client-Architektur hat. Und das ist halt die Lösung in Javascript.
Benutzeravatar
Dennis89
User
Beiträge: 1186
Registriert: Freitag 11. Dezember 2020, 15:13

Da habe ich mich schlecht ausgedrückt. Ich habe das so verstanden: Der `onMounted` - Event wird zu Beginn, ich denke mal mit `.mount('#app')` ausgelöst und dann werden die Daten geladen. Während dessen können aber andere Sachen ausgeführt werden, weil `await` wartet, bis die Daten da sind.
Mit "von Anfang an" meinte ich, dass die Daten nicht erst geladen werden, wenn der User aktiv ein Event (Bspw. Buttonklick) auslöst.

Mit nebenläufiger Programmierung hatte ich noch nie wirklich Kontaktpunkte. Ich lese zwar in den Themen hier im Forum immer mit, aber um zu verstehen, muss ich es anwenden. Von dem her bin ich eigentlich ganz froh darüber, dass ich das anwenden muss. Wenn eure Nerven das auch mit machen, dann bin ich optimistisch 😁

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Antworten