Flask nur ein bestimmtes Element ändern

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

Guten Abend
Ich bin ein völliger Neuling was flask und Jinja anbelangt. Was ich machen will, ist nur ein bestimmtes Element eines Template ändern, ohne dass das ganze Template neu gerendert wird. Meine Websuche hat nicht so viel gebracht, kann aber auch daran liegen, dass ich nicht nach dem Richtigen gesucht habe.

Python:

Code: Alles auswählen

import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect

app = Flask(__name__)
app.config['SECRET_KEY'] = 'my secret key'

@app.route('/')
def index():
    text = 'myAdmin_0'
    id = 'pageTitleBar'
    return render_template('index.html', text=text, id=id)


@app.route('/newtitle')
def newtitle():
    text = 'myAdmin_1'
    id_ = 'pageTitleBar'
    
    return text, id
Template:

Code: Alles auswählen

<!doctype html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="static/css/index.css">

  </head>
  <body>
    <div class='mainContainer'>
      <div class='pageTitleBar' id='pageTitleBar'>
           {{text}}
      </div>
      <a class='newTitleButton' href="{{ url_for('newtitle' )}}">
        New Titel
      </a>
    </div>

  </body>
</html>
Dass das so nicht funktionieren kann weiss ich. Es geht mir eher darum um zu Zeigen was ich tun will.

Danke für Rückmeldungen

Christoph
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

Das Zeigen verschlimmbessert die Vorgabe nur.

Was heißt rendern bei dir? Das Rendern in Flask oder das Rendern Im Browser?
ChristophS
User
Beiträge: 52
Registriert: Montag 7. August 2017, 12:52

Danke für Deine schnelle Antwort.

Wie gesagt ich bin Anfänger.
Es geht um das 'render template' das, so wie ich es verstanden habe, wird das im Browser gemacht.
Was funktioniert Ist:

Code: Alles auswählen

@app.route('/newtitle')
def newtitle():
    text = 'myAdmin_1'
    id_ = 'pageTitleBar'
    
    return render_template('index.html', text=text, id=id_)
Aber das rendert die ganze Site, was ich nicht will. Ich will nur den pageTitleBar ändern.
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ChristophS: `render_template()` wird nicht im Browser gemacht, das passiert auf dem Server, bevor das HTML zum Browser geschickt wird.

Das was Du willst geht beispielsweise mit JavaScript das zum Beispiel per `fetch()`-API den Text vom Server abfragt und dann über die ID `pageTitleBar` das <div> ermittelt und dort den Inhalt austauscht.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

s geht um das 'render template' das, so wie ich es verstanden habe, wird das im Browser gemacht.
Nein, wird es nicht. Das Template wird immer serverseitig gerendert, dabei kommt HTML raus, das wird dann an den Browser geschickt und der rendert das HTML zur Bildschirmdarstellung.

Du kannst im Browser die angezeigte Webseite per JavaScript ändern. Je nach dem, was du vorhast, musst du die Daten vom Server holen, Stand der Dinge ist die JavaScript fetch-API dafür. Oder du lädst halt die ganze Seite neu. Was besser ist kann man so nicht sagen, ohne das du konkret sagst, was du vor hast.

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

Wie schon die Vorredner geschrieben haben, braucht man dafür JavaScript:

Code: Alles auswählen

import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect

app = Flask(__name__)
app.config['SECRET_KEY'] = 'my secret key'

@app.route('/')
def index():
    text = 'myAdmin_0'
    return render_template('index.html', text=text)


@app.route('/newtitle')
def newtitle():
    text = 'myAdmin_1'
    id_ = 'pageTitleBar'
    return {"text": text, "id": id_}

if __name__ == "__main__":
    app.run()

Code: Alles auswählen

<!doctype html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="static/css/index.css">

  </head>
  <body>
    <div class='mainContainer'>
      <div class='pageTitleBar' id='pageTitleBar'>
           {{text}}
      </div>
      <a class='newTitleButton' href="#">
        New Titel
      </a>
    </div>
    <script>
async function update_title(event) {
   event.preventDefault();
   const response = await fetch("/newtitle");
   if(response.ok) {
      const data = await response.json();
      document.querySelector(`#${data.id}`).innerText = data.text;
   }
}

document.querySelector(".newTitleButton").addEventListener("click", update_title);
    </script>
  </body>
</html>
ChristophS
User
Beiträge: 52
Registriert: Montag 7. August 2017, 12:52

@Sirius
Tut mir leid, dass ich nicht erst jetzt bei Dir bedanke. Wie schon so oft hast Du mir bei Deinem Input geholfen nicht nur eine Aufgabe zu lösen sondern gleich mehrere Problemstellungen aufs mal zu lösen.

Eine weitere Problemstellung bei meinem Beispiel war, dass ich mit dem 'title' noch etwas 'anfangen' will. Um wirklich zu verstehen suche ich gerne selber nach Lösungen (KI ist für mich kein Thema, ebenso woe 'copy paste'). Deine Antworten ermöglichen mir 'richtig' nach Lösungen zu suchen.

Mein javascript sieht nun so aus:

Code: Alles auswählen

  <script>

    async function update_title(event) {
      event.preventDefault();
      const title = document.querySelector(".pageTitleBar").innerText
      
      const response = await fetch(
        "/newtitle", {
          "method": "POST",
          "body": title,
        }
      );

      if(response.ok) {
        const data = await response.json();
        document.querySelector(`#${data[0].id}`).innerText = data[0].text;
      }
    };

    document.querySelector(".newTitleButton").addEventListener("click", update_title);

  </script>
Die Python Seite so:

Code: Alles auswählen

@app.route('/newtitle', methods=['POST'])
def newtitle():
    title = request.data
    titele_index = int(title.decode('ascii').split('_')[1])
    text = 'myAdmin_' + str(titele_index + 1)
    id_ = 'pageTitleBar'
    return [{"text": text, "id": id_}]
Gruss Christoph
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Eine weitere Problemstellung bei meinem Beispiel war, dass ich mit dem 'title' noch etwas 'anfangen' will
Wo denn? Serverseitig oder Clientseitig? So oder so spricht da prinzipiell nichts gegen. Clientseitig kannst du zwischen

Code: Alles auswählen

const data = await response.json();
document.querySelector(`#${data.id}`).innerText = data.text;
noch beliebig `data` manipulieren mit allem, was JavaScript so her gibt.

Deine gezeigte Änderung

Code: Alles auswählen

return [{"text": text, "id": id_}]
macht nicht so richtig ist. Du verpackst ein JSON-Objekt in einen JSON-Array und bekommst einen 1-elementigen Array und das eine Element ist ein JSON Objekt. Oder anders: da ist eine Hülle überflüssig, zumindest so wie gezeigt. Wenn du warum auch immer einen Array statt ein Objekt willst, dann wäre

Code: Alles auswählen

return [text, id_]
der Weg.

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

@noisefloor

Danke für die Rückmeldung.
Mein Beispiel ist sehr Einfach gehalten und erfüllt ausser dem Zweck, dass ich die Zusammenhänge lernen und kennen will nichts weiteres.

Klarerweise müsste die Variable 'title' in python 'index_template_title_text' heissen.
Wo denn? Serverseitig oder Clientseitig? So oder so spricht da prinzipiell nichts gegen. Clientseitig kannst du zwischen
Serverseitig, ich mache künftig eine sqlite Abfrage und gebe das Ergebnis an den Client zurück der dann damit irgendetwas macht.

Du hast recht die Hülle ist eigentlich überflüssig. Sobald ich aber nicht nur ein Objekt weiterreichen will, dann ist diese nötig. Mir ging es darum zu testen wie das funktioniert.

Code: Alles auswählen

return [{'text':' text1', "id": 'id1'}, {'text':' text2', "id": 'id2'}]
Und damit dann auf dem Client zB. eine Liste zu füllen. JASON deshalb, weil ich mich eher an einen Namen erinnern kann, als an die Reihenfolge der Elemente.

Lieber Gruss

Christoph
Antworten