Flaskform mit Default werten füllen

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
nieselfriem
User
Beiträge: 135
Registriert: Sonntag 13. Januar 2013, 16:00

Hallo,

ich möchte gern FlaskForm-Formular mit default Werten befüllen. Leider hat wohl die klasse keine Möglichkeit mit einem Konstruktor zu arbeiten oder ich begreife nicht, wie ich ihn richtig einsetze

Dazu habe ich mal folgendes zusammengeschrieben, was leider nicht funktioniert.

Code: Alles auswählen

class HostForm(FlaskForm):
    def __init__(self, infos):
        self.infos = infos
        self.id = self.infos[0]
        self.name = self.infos[1]
        self._host = self.infos[2]
        self.env = self.infos[5]
        if self.env == "prod":
            self.env = "Produktion"
        elif self.env == "Test1":
            self.env = "Test1"
        elif env == "Test2":
            self.env = "Test2"

    id = StringField("Id", validators=[
        DataRequired()], default=id)
    name = StringField("Name", validators=[
        DataRequired()], default=pz_name.capitalize())
    hostname = StringField("Host", validators=[
                           DataRequired()], default=host)
    env = StringField("Umgebung", validators=[
        DataRequired()], default=env)
    submit = SubmitField("Test")
Ich bekomme dabei diese Fehlermeldung:

Code: Alles auswählen

  File "e:\program files\python\python36\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "e:\program files\python\python36\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "E:\Program Files\Python\Python36\Scripts\flask.exe\__main__.py", line 9, in <module>
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 966, in main
    cli.main(prog_name="python -m flask" if as_module else None)
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 586, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "e:\program files\python\python36\lib\site-packages\click\core.py", line 717, in main
    rv = self.invoke(ctx)
  File "e:\program files\python\python36\lib\site-packages\click\core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "e:\program files\python\python36\lib\site-packages\click\core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "e:\program files\python\python36\lib\site-packages\click\core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "e:\program files\python\python36\lib\site-packages\click\decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "e:\program files\python\python36\lib\site-packages\click\core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 848, in run_command
    app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 305, in __init__
    self._load_unlocked()
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 330, in _load_unlocked
    self._app = rv = self.loader()
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 388, in load_app
    app = locate_app(self, import_name, name)
  File "e:\program files\python\python36\lib\site-packages\flask\cli.py", line 240, in locate_app
    __import__(module_name)
  File "E:\Service-Repos\hls\hls_master\infra\docker\hls-versions-monitor-db\src\flaskform_test.py", line 4, in <module>
    from operations import *
  File "E:\Service-Repos\hls\hls_master\infra\docker\hls-versions-monitor-db\src\operations.py", line 7, in <module>
    class HostForm(FlaskForm):
  File "E:\Service-Repos\hls\hls_master\infra\docker\hls-versions-monitor-db\src\operations.py", line 24, in HostForm
    DataRequired()], default=id)
NameError: name 'id' is not defined
Nun meine Frage. Wie bekomme ich default-Werte am elegantesten in mein Formular?

VG niesel
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@nieselfriem: Das ist komisch weil es eine eingebaute `id()`-Funktion gibt, da sollte es also eigentlich nie einen `NameError` geben, auch wenn das natürlich falsch ist die `id()`-Funktion da als Defaultwert verwenden zu wollen. Hast Du da irgendwo ein ``del id`` auf Modulebene stehen‽

Dann solltest Du die Klassenattribute *vor* der `__init__()` definieren. Danach kommt das reichlich unerwartet.

In der `__init__()` rufst Du die `__init__()` der Basisklasse gar nicht auf, die macht aber wichtige Sachen und möchte auch Werte dafür haben sofern nicht alle Felder einen Defaultwert haben.

Die Defaultwerte die Du angibst sind insgesamt etwas fragwürdig. Die müssen ja zum Zeitpunkt der Definition der *Klasse* bekannt sein. Du schreibst die aber alle klein, also sind das entweder keine Konstanten, oder sie sind falsch geschrieben. Man darf auch in der `__init__()` nicht einfach die Attribute selbst überschreiben, das sind ja komplexere Objekte und nicht einfache Werte. Ich würde eher keine `__init__()` selbst implementieren und diese Ersetzungen bei `env` eher als Filter beim Feld lösen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
nieselfriem
User
Beiträge: 135
Registriert: Sonntag 13. Januar 2013, 16:00

Ich hatte ein Präfix vor id, den habe ich aber aus gründen entfernt. Deshalb stand fälschlicherweise nur noch id da.
Nun weiß ich nicht, was du mit dem Satz
Dann solltest Du die Klassenattribute *vor* der `__init__()` definieren. Danach kommt das reichlich unerwartet.
meinst. In jeder Anleitung, die ich so finde. Definiere ich im Konstruktor doch die Variablen einer Klasse.
In der `__init__()` rufst Du die `__init__()` der Basisklasse gar nicht auf, die macht aber wichtige Sachen und möchte auch Werte dafür haben sofern nicht alle Felder einen Defaultwert haben.
Das könnte der Schlüssel für mein Problem sein. Aber das weiß ich eben nicht, wie das hier funktioniert. Hier liefert mir VS-Code folgendes Snipped:

Code: Alles auswählen

class HostForm(FlaskForm):
    def __init__(self, formdata=_Auto, **kwargs):
        super().__init__(formdata=formdata, **kwargs)
Aber wie kann ich das Verwenden um dort meine Defaulwerte für meine Formularkomponenten reinzupusten?

vg niesel
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@nieselfriem: In der `__init__()` werden die Attribute des Exemplars definiert, nicht die der Klasse. Die auf der Klasse gelten für *alle* Exemplare weil sie auf der *einen* Klasse definiert sind, aus der die Exemplare erstellt werden. `FlaskForm`\s haben Klassenattribute und die sollte man definieren bevor man die `__init__()` definiert, weil das die Reihenfolge ist in der Leser das erwarten.

Ich bleibe dabei das man bei `FlaskForm` eher keine eigene `__init__()` erstellt. Und ich weiss auch nicht ob wir unter Defaultwerte das gleiche verstehen. Das sind die Werte die genommen werden wenn man keine angibt. Die müssen also im Grunde konstant sein. So etwas wie eine ID kann doch eigentlich keinen Defaultwert haben.

Ich habe so ein bisschen das Gefühl Du solltest erst einmal ganz normal mit der gegebenen `__init__()` arbeiten und dann mal erklären was Du zusätzlich brauchst, was die nicht schon leistet. Also ein komplettes Beispiel das zeigt was da am Ergebnis dann noch nicht so ist wie Du das haben möchtest.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
nieselfriem
User
Beiträge: 135
Registriert: Sonntag 13. Januar 2013, 16:00

Hi, im Grunde will ich eigentlich nichts weltbewegendes.

die Variable Infos ist ein Tupel welches aus einer Datenbankabfrage kommt.

Code: Alles auswählen

infos =("1", "Köln", "https://hostname.de", "bla", "blub", "test1")
Nun möchte ich ein Formular erzeugen das in html wie folgt aussieht

Code: Alles auswählen

<form>
  <label for="hostid">HostId:
    <input id="hostid" name="hostid" value="1">
  </label>
  <label for="ort">Ort: 
    <input id="ort" name="ort" value="Köln">
  </label>
  <label for="hostname">Name: 
    <input id="hostname" name="hostname" value="https://hostname.de">
  </label>
  <input type="submit" value="senden">
</form>
Das bedeutet, in einem vorherigen Formular, das in einer Tabelle eingebettet, wählt der User einen Host aus, klickt auf einen Button und die Datenbankanfrage ermittelt die Daten der Auswahl die getätigt wurde. Dadurch soll dann das obige Formular mit den Werten aus der Datenbank erscheinen um diese dann ggf. zu ändern. Aber sie sollen erst einmal drinnen stehen.

So ist es ja auch möglich eine Dropdownliste wie folgt zu befüllen

https://hackersandslackers.com/flask-wtforms-forms/

Code: Alles auswählen

 class SignupForm(FlaskForm):
    """Sign up for a user account."""
    email = StringField('Email', [
        Email(message='Not a valid email address.'),
        DataRequired()])
    password = PasswordField('Password', [
        DataRequired(message="Please enter a password."),
    ])
    confirmPassword = PasswordField('Repeat Password', [
            EqualTo(password, message='Passwords must match.')
            ])
    title = SelectField('Title', [DataRequired()],
                        choices=[('Farmer', 'farmer'),
                                 ('Corrupt Politician', 'politician'),
                                 ('No-nonsense City Cop', 'cop'),
                                 ('Professional Rocket League Player', 'rocket'),
                                 ('Lonely Guy At A Diner', 'lonely'),
                                 ('Pokemon Trainer', 'pokemon')])
    website = StringField('Website', validators=[URL()])
    birthday = DateField('Your Birthday')
    recaptcha = RecaptchaField()
    submit = SubmitField('Submit')

aber ich will z.B. diese Liste nicht im Code fest definieren sondern durch eine Methode erzeugen lassen um sie dann in das Formular übergeben zu können.

Ich hoffe ich konnt emich nun verständlich machen, was ich eigentlich will. ;)

VG niesel
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mit anderen Worten es gibt schon mal genau gar keinen Defaultwert, weil die Werte ja alle aus der Datenbankabfrage kommen. Und Du brauchst auch keine eigene `__init__()` sondern kannst die vorhandene verwenden. Die Dokumentation sagt das es ganze *vier* verschiedene Wege gibt die Daten der `wtforms.Form.__init__()` mit auf den Weg zu geben. Musst Dir halt einen davon aussuchen und den dann gehen. (`FlaskForm` ergänzt das noch um einen fünften Weg, der hier aber nicht sinnvoll ist.)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten