BooleanField anhand von gegebenen Daten (nicht )abhaken

Django, Flask, Bottle, WSGI, CGI…
Antworten
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

Hallo Flask-Coder :-)


ich möchte gerne ein mit Hilfe von Jinja2/WTForms (in Flask) Textfelder anhand gespeicherter Daten füllen, was mir an sich gelingt. siehe:

Code: Alles auswählen

 
 <div class="form-group row">
 <div class="col-xs-10">
{{ wtf.form_field(form.name, class='form-control',value=person['name']) }}
 </div>  
Aber wie schaffe ich es das ich Booleanfelder richtig "füllen" kann ?

Denn meine Vorgehensweise ist wohl falsch:

Code: Alles auswählen

<div class="form-check row">
<div class="col-xs-10">
{{ wtf.form_field(form.interested class='form-check',value=person['interested']) }}
</div>
Formklasse:

Code: Alles auswählen

class PersonForm(FlaskForm):
    name = StringField('Name: ', validators=[InputRequired(),
                                               Length(min=2, max=510)])
    #...............................
   interested  = BooleanField('Interessiert: ')
route:

Code: Alles auswählen

@person.route('/persons', methods=['GET'])
def get_skills():
    all_persons = get_all_persons()
    person_form = PersonForm()
    return render_template('persons.html', form=person_form, person_List=all_persons)
model:

Code: Alles auswählen

class Persons(db.Model):
    __tablename__ = "persons"
    id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
    name = db.Column(nullable=False)
    #...............................
    interested = db.Column(db.Boolean, nullable=False)

Hinweise: Die get_all_persons() gibt mir alles richtig aus und interested ist ein einfaches boolean. Ich möchte erreichen das wenn interested True ist das dass BooleanField "abgehakt" wird.

Diese Kleinigkeit macht mich noch verrückt, wäre froh wenn mir jemand schreiben könnte was ich falsch mache. :D

Danke :)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PythonCodingFun: Das sieht komisch aus wie Du das Feld erzeugst. Normalerweise füllt man das `Form`-Objekt mit Werten bevor man das dem Template übergibt. Und im Template steht dann für die beiden Beispiele:

Code: Alles auswählen

{{ form.name(class_="form-control") }}
{{ form.interested(class_="form-check") }}
Wie der Wert aus dem `Form` in das HTML-Element kommt, ist nicht Deine Aufgabe, sondern die des `Widget` das zu dem `Field` im `Form` gehört.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

__blackjack__ hat geschrieben: Donnerstag 11. August 2022, 09:45 @PythonCodingFun: Das sieht komisch aus wie Du das Feld erzeugst. Normalerweise füllt man das `Form`-Objekt mit Werten bevor man das dem Template übergibt. Und im Template steht dann für die beiden Beispiele:
Ich möchte aber die Felder (in einem Modal) bearbeitbar machen, was mir bei name usw. gelingt aber nicht bei dem Booleanfield
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PythonCodingFun: Das ändert nichts an meiner Antwort. Mach es wie es vorgesehen ist, und WTForms macht die Arbeit, die Du hier manuell versuchst nachzubasteln.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

__blackjack__ hat geschrieben: Donnerstag 11. August 2022, 10:26 @PythonCodingFun: Das ändert nichts an meiner Antwort. Mach es wie es vorgesehen ist, und WTForms macht die Arbeit, die Du hier manuell versuchst nachzubasteln.
Gut, okay, ich habe es so gemacht

Code: Alles auswählen

{{ form.interested(class_="form-check") }}

Aber das Problem bleibt :shock:
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PythonCodingFun: Welches Problem? Das ist ja nicht alles was Du gemacht hast, Du hast ja auch Code geschrieben der das `Form`-Objekt mit den Daten füllt bevor das an das Template geht. Falls nicht, fehlt das halt noch.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

__blackjack__ hat geschrieben: Donnerstag 11. August 2022, 11:34 @PythonCodingFun: Welches Problem? Das ist ja nicht alles was Du gemacht hast, Du hast ja auch Code geschrieben der das `Form`-Objekt mit den Daten füllt bevor das an das Template geht. Falls nicht, fehlt das halt noch.
Vielleicht hab ich mich ein wenig falsch ausgedrückt :)

Ich möchte ein Modal öffnen was es mir ermöglicht
1. Die Informationen zu sehen (Name usw.)
2. Diese Information zu ändern

was bei allen Feldern soweit auch klappt, nur eben nicht bei dem Boolean-Feld. Beim Debuggen des Python-Codes sehe ich das die liste richtig befüllt wurde der Wert interested ein True oder False hat.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PythonCodingFun: Wenn es einen modalen Dialog für mehrere Personen gibt, dann kannst Du das doch sowieso nicht im Template schon mit Daten füllen. Es sei denn Du machst da für jede Person einen eigenen Dialog, was irgendwie ziemlich krass wäre, IMHO.

In dem Fall muss das füllen des `Form`-Objektes mit der jeweiligen Person im Template passieren.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

__blackjack__ hat geschrieben: Donnerstag 11. August 2022, 12:13 @PythonCodingFun: Wenn es einen modalen Dialog für mehrere Personen gibt, dann kannst Du das doch sowieso nicht im Template schon mit Daten füllen. Es sei denn Du machst da für jede Person einen eigenen Dialog, was irgendwie ziemlich krass wäre, IMHO.
Nein, ich iteriere durch die Personen-Liste durch und alle Werte kommen in eine Tabelle. Und dann kann ich für jede Person ein Modal "anbieten".
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PythonCodingFun: Na dann kannst Du das doch sowieso noch nicht im Template füllen, weil je nach dem welche Person angeklickt wurde um den Dialog anzubieten, müssen da doch andere Daten rein. Da der Server nicht weiss welche Person angeklickt wird, muss das im Browser passieren. Mittels JavaScript.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

__blackjack__ hat geschrieben: Donnerstag 11. August 2022, 12:48 @PythonCodingFun: Na dann kannst Du das doch sowieso noch nicht im Template füllen, weil je nach dem welche Person angeklickt wurde um den Dialog anzubieten, müssen da doch andere Daten rein. Da der Server nicht weiss welche Person angeklickt wird, muss das im Browser passieren. Mittels JavaScript.
so wie ich es in der Frage geschildert habe, funktioniert es so mit Textfeldern (nur halt nicht mit Booleanfeldern^^)

z.B
Ausschnitt aus dem Modal:

Code: Alles auswählen

<div class="form-group row">
 <div class="col-xs-10">
{{ wtf.form_field(form.name, class='form-control',value=person['name']) }}
 </div>  
Und ich nutze kein JS sondern Flask-Bootstrap und Jinja
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PythonCodingFun: Das kann so nicht funktionieren es sei denn Du erzeugst das eben *doch* für jede Person. Denn woher sollte *ein* modaler Dialog denn sonst wissen welche Person er darstellen soll? Das geht nicht statisch bzw. dynamisch auf dem Server. Da wären wir dann wieder bei „krass“. IMHO.

Letztlich bleibt die Antwort aber immer noch die gleiche. Füll das `Form`-Objekt mit Daten und lass das rendern das zum `Field` gehörende `Widget` erledigen, anstatt das selbst machen zu wollen. Den Code dafür gibt es ja schon, den muss man nicht noch mal selbst nachbauen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

__blackjack__ hat geschrieben: Donnerstag 11. August 2022, 13:05 @PythonCodingFun: Das kann so nicht funktionieren es sei denn Du erzeugst das eben *doch* für jede Person. Denn woher sollte *ein* modaler Dialog denn sonst wissen welche Person er darstellen soll? Das geht nicht statisch bzw. dynamisch auf dem Server. Da wären wir dann wieder bei „krass“. IMHO.
Ich schrieb doch das ich durch die Personenliste durch-iteriere alles in eine Tabelle (html+Bootstrap) schreibe und das was ich (exemplarisch) gezeigt hab für alle Personen aus der DB.

Ich hole mal weiter aus :)
Jede Zeile (also jede Person) hat einen Button "Bearbeiten" (o.ä benannt) bei dem ein Modal geöffnet wird und mir alle Werte dieser Person gezeigt werden und ich diese ändern kann (wie gesagt klappt auch so bei String/Textfeldern etc.)
einfachTobi
User
Beiträge: 491
Registriert: Mittwoch 13. November 2019, 08:38

Die Daten für die einzelnen Modals müssen dann ja schon fest übergeben werden, oder? Sprich du hast nachdem das Template gerendert wurde ein Modal für jede Person im Quelltext stehen. Das macht im in der Regel nicht so, sondern lädt diese Daten dynamisch, wenn das Modal geöffnet wird oder holt eben das Modal nachträglich vom Server, wobei das vermutlich eher umständlich ist.
Mit "Form vorher befüllen" ist gemeint, dass das Form bereits mit den nötigen Inhalten erzeugt wird, bevor es dem Template übergeben wird:

Code: Alles auswählen

@person.route('/persons', methods=['GET'])
def get_skills():
    all_persons = get_all_persons()
    person_form = PersonForm(name="Hans", interested=True)
    return render_template('persons.html', form=person_form, person_List=all_persons)
Daher führt das in Kombination mit meinem ersten Absatz zu einer gewissen Verwunderung.
Der Code oben würde so auch nicht so richtig Sinn ergeben, weil du ja mehrere Forms erzeugen willst:

Code: Alles auswählen

@person.route('/persons', methods=['GET'])
def get_skills():
    all_persons = get_all_persons()
    forms = [PersonForm(name=person.name, interested=person.interested) for person in all_persons]
    return render_template('persons.html', forms=forms, person_List=all_persons)
Dann kannst du im Template über alle Forms iterieren und diese erstellen lassen:

Code: Alles auswählen

{% for form in forms %}
  {{ form.name(class_="form-control") }}
  {{ form.interested(class_="form-check") }}
{% endfor %}
Und genau das ist ungewöhnlich, wenn es um optional angezeigte Daten geht. Hier würde man die Daten (das Form) erst dann abrufen, wenn auch der Modal angezeigt werden soll, also geklickt wurde, statt für alle Personen bereits ein Modal vorzuhalten.
Zuletzt geändert von einfachTobi am Donnerstag 11. August 2022, 13:37, insgesamt 1-mal geändert.
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

@einfachTobi ja das was Du da aufzeigst ist natürlich besser aber ich hab für den unüblichen Weg entschieden es ist eigentlich nur kleiner Prototyp, habe gerade ein schönes Beispiel gefunden mit dem man es noch besser machen kann
Link: https://blog.miguelgrinberg.com/post/be ... -templates

Aber ich werde nur mit dem Booleanfield wahnsinnig (denn Textfields funktionieren ja^^, was mich dann auch verwundert), wenn das klappt baue ich die Anwendung mal um ;)
einfachTobi
User
Beiträge: 491
Registriert: Mittwoch 13. November 2019, 08:38

Ich sehe nicht wie dein Link dein Problem lösen sollte. Es geht doch darum, dass du zwar WTForms verwendest, aber dann im Template dagegen arbeitest.
Hier ein vollständiges Minimalbeispiel:

Code: Alles auswählen

from flask import Flask, render_template
from wtforms import Form, StringField, BooleanField

app = Flask(__name__)


class Person:
    def __init__(self, name, interested):
        self.name = name
        self.interested = interested


class PersonForm(Form):
    name = StringField(label="Name")
    interested = BooleanField(label="Interessiert", default=True)


@app.route("/")
def foo():
    persons = [Person("Hans-Werner", True), Person("Gitte", False), Person("Uta", True)]
    forms = [PersonForm(name=person.name, interested=person.interested) for person in persons]
    return render_template("index.html", forms=forms)


if __name__ == '__main__':
    app.run()
index.html

Code: Alles auswählen

<!DOCTYPE html>
<html lang="en">
<body>
{% for form in forms %}
<form method="GET" action="/">
  <div>
      {{ form.name.label }}:
      {{ form.name }}
      {{ form.interested.label }}:
      {{ form.interested }}
  </div>
</form>
{% endfor %}
</body>
</html>
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

Danke an alle jetzt hab ich wieder was dazugelernt :)
PythonCodingFun
User
Beiträge: 49
Registriert: Mittwoch 22. September 2021, 14:01

einfachTobi hat geschrieben: Donnerstag 11. August 2022, 13:29 Die Daten für die einzelnen Modals müssen dann ja schon fest übergeben werden, oder? Sprich du hast nachdem das Template gerendert wurde ein Modal für jede Person im Quelltext stehen. Das macht im in der Regel nicht so, sondern lädt diese Daten dynamisch, wenn das Modal geöffnet wird oder holt eben das Modal nachträglich vom Server, wobei das vermutlich eher umständlich ist.
Wenn man eine Person-Edit Seite ohne Modal realisiert, sprich in einer eigenen HTML/Jinja Seite, benötigt man doch sicherlich auch so was wie eine Session ? Damit das Back-End "weiß" um welche Entität es sich schlussendlich handelt, oder ? Wären Sessions da eine richtig Wahl oder gäbe es da bessere Ansätze ?
einfachTobi
User
Beiträge: 491
Registriert: Mittwoch 13. November 2019, 08:38

Ich würde das Datum, das die Person eindeutig identifiziert (in der Regel eine ID) einfach mit dem Formular/dem Link mitschicken. In der Session speichert man eher Daten, die zum Benutzer der Seite gehören.
Also sowas wie:

Code: Alles auswählen

# HTML
<a class="btn" href="{{ url_for('edit_person', person_id=person.id) }}" role="button">

# Python 
@app.route("/person/bearbeiten/<person_id>")
def edit_person(person_id):
    person = get_person(person_id)
    return render_template("edit.html", person=PersonForm(name=person.name, interested=person.interested))
Antworten