default Angabe in Auswahlfeld ändern

Django, Flask, Bottle, WSGI, CGI…
Antworten
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Ich möchte den Schülerinnen und Schüler ermöglichen, sich auszusuchen, ob in ihrer Übersichtseite nur die Aufgaben des aktuellen Halbjahres oder alle bereits gemachten Aufgaben angezeigt werden. Nachdem eine Auswahl getroffen wurde, zeigt das Auswahlfeld aber immer die erste Einstellung der Auswahlmöglichkeiten an. Ich hätte gerne, dass dort die letzte Auswahl steht. Es ist mir noch nicht gelungen, diese derart ändern. Entweder habe ich gedacht, ich könnte das mit inital machen oder halt einfach die Reihenfolge der Auswahlmöglichkeiten ändern.
In stackoverflow https://stackoverflow.com/questions/657 ... hoicefield habe ich mehrere Möglichkeiten gefunden, aber entweder verstehe ich sie nicht oder ich mache was falsch.
Ich habe mich dort für die Möglichkeit E entschidien und in den forms.py:

Code: Alles auswählen

class UebersichtFilter(forms.Form):
    auswahl = forms.ChoiceField()
und in views.py:

Code: Alles auswählen

        choices=[("Halbjahr",'aktuelles Halbjahr'),("all",'Alle Aufgaben'),]
        form_filter = UebersichtFilter(choices)
Ich bekomme den Fehler:

Code: Alles auswählen

AttributeError: 'list' object has no attribute 'get'
für die Zeile "{{form_filter.auswahl}}" in "uebersicht.html":

Code: Alles auswählen

    <form action="{% url 'uebersicht' %}" method="POST">
        {% csrf_token %}
        <h2 style= "text-align: left;"> Zeitraum: 
            <button type="button">
                {{form_filter.auswahl}}
            </button type="button">
            <button type="button">
                <input name="filter" type="submit" value="anwenden">
            </button type="button">
        </h2>
    </form>
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Nachdem ich das hier nicht hinbekommen habe und die Hilfen in stackoverflow nicht verstehe, habe ich mir damit geholfen, dass ich in meinen Userprofilen ein Feld "alle_zeigen" eingfügt und zwei Formulare erstellt:

Code: Alles auswählen

class UebersichtHalbjahr(forms.Form):
    auswahl = forms.ChoiceField(choices=[("Halbjahr",'aktuelles Halbjahr'), ("all",'Alle Aufgaben'),])

class UebersichtAlle(forms.Form):
    auswahl = forms.ChoiceField(choices=[("all",'Alle Aufgaben'),("Halbjahr",'aktuelles Halbjahr'), ])
und in meinen views.py ist mir nichts besseres eingefallen als:

Code: Alles auswählen

        alle_zeigen = profil.alle_zeigen
        if alle_zeigen:
            form = UebersichtAlle
        else:
            form = UebersichtHalbjahr
        if req.method == 'POST':
            auswahl = form(req.POST)
            if auswahl.is_valid(): 
                auswahl = auswahl.cleaned_data['auswahl']
                profil.alle_zeigen = True if auswahl == "all" else False
                profil.save()
        protokoll = Protokoll.objects.filter(profil=profil)
        alle_zeigen = profil.alle_zeigen
        if alle_zeigen:
            form = UebersichtAlle
        else:
            form = UebersichtHalbjahr
            protokoll = Protokoll.objects.filter(profil=profil, schuljahr=profil.schuljahr, halbjahr=profil.halbjahr)
Das funktioniert ... aber schön ist anders ...
Benutzeravatar
noisefloor
User
Beiträge: 4172
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Du kannst den initial ausgewählten Wert beim Instanzieren der Form vorgeben:

Code: Alles auswählen

>>> from django import forms
>>> class Tasks(forms.Form):
...     select_task = forms.ChoiceField(choices=[('a', 'all'), ('1', 'first semester'), ('2', 'second semester')])
...
>>> task = Tasks()
>>> task.as_p()
'<p>\n    <label for="id_select_task">Select task:</label>\n    <select name="select_task" id="id_select_task">\n  <option value="a">all</option>\n\n  <option value="1">first semester</option>\n\n  <option value="2">second semester</option>\n\n</select>\n    \n    \n      \n    \n  </p>'
>>> task = Tasks(initial={'select_task': '2'})
>>> task.as_p()
'<p>\n    <label for="id_select_task">Select task:</label>\n    <select name="select_task" id="id_select_task">\n  <option value="a">all</option>\n\n  <option value="1">first semester</option>\n\n  <option value="2" selected>second semester</option>\n\n</select>\n    \n    \n      \n    \n  </p>'
>>>
Gruß, noisefloor
Benutzeravatar
noisefloor
User
Beiträge: 4172
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Nachtrag: oder bei der Instanz der Form die Werte für `choices` überschreiben:

Code: Alles auswählen

>>> from django import forms
>>> class Tasks(forms.Form):
...     select_task = forms.ChoiceField(choices=[('a', 'all'), ('1', 'first semester'), ('2', 'second semester')])
...
>>> task = Tasks()
>>> task.fields['select_task'].choices = [('3', 'foo'), ('4', 'spam')]
>>> task.as_p()
'<p>\n    <label for="id_select_task">Select task:</label>\n    <select name="select_task" id="id_select_task">\n  <option value="3">foo</option>\n\n  <option value="4">spam</option>\n\n</select>\n    \n    \n      \n    \n  </p>'
>>>
Gruß, noisefloor
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Das sieht so aus, als könnte es mir helfen. Danke schonmal. Aber bedenke bitte, ich bin von tieferem Verständnis leider weit entfernt. Kannst du mir das bitte mal genauer erklären?
Also der erste Teil

Code: Alles auswählen

>>> from django import forms
>>> class Tasks(forms.Form):
...     select_task = forms.ChoiceField(choices=[('a', 'all'), ('1', 'first semester'), ('2', 'second semester')])
...
entspricht meinem Code in forms.py

Code: Alles auswählen

class UebersichtHalbjahr(forms.Form):
    auswahl = forms.ChoiceField(choices=[("Halbjahr",'aktuelles Halbjahr'), ("all",'Alle Aufgaben'),])
Ich vermute, der letzte Teil

Code: Alles auswählen

'<p>\n    <label for="id_select_task">Select task:</label>\n    <select name="select_task" id="id_select_task">\n  <option value="3">foo</option>\n\n  <option value="4">spam</option>\n\n</select>\n    \n    \n      \n    \n  </p>'
kommt in mein Template. Da gibt wiederum der erste Teil das Label aus und die beiden folgenden Teile ersetzen die Einträge im Auswahlfenster.
Was aber macht der mittlere Teil. Ich habe mal versucht ihn angepasst in mein view zu übernehmen

Code: Alles auswählen

        form = UebersichtAlle()
        form.fields('auswahl').choices = [('1', 'eins'), ('2', "Zwei")]
        form.as_p()
... bekomme dann aber die Fehlermedung

Code: Alles auswählen

    form.fields('auswahl').choices = [('1', 'eins'), ('2', "Zwei")]
TypeError: 'dict' object is not callable
Diese Meldung kenne ich schon von den Versuchen die obengenannten Vorschläge die ich in stackoverflow gefunden habe umzusetzen. Was mache ich falsch?
Benutzeravatar
noisefloor
User
Beiträge: 4172
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Pitwheazle hat geschrieben: Donnerstag 30. Januar 2025, 17:20 Also der erste Teil
...
entspricht meinem Code in forms.py
...
Korrekt.
Pitwheazle hat geschrieben: Donnerstag 30. Januar 2025, 17:20 Ich vermute, der letzte Teil
...
kommt in mein Template.
Korrekt. `form.as_p` oder `form.as_ul` oder ... rufst du im Template auf, dass rendert die Form nach HTML. Was anderes mache ich in der Shell-Session auch nicht, nur halt als Ausgabe in die Konsole.
Pitwheazle hat geschrieben: Donnerstag 30. Januar 2025, 17:20 Was aber macht der mittlere Teil. Ich habe mal versucht ihn angepasst in mein view zu übernehmen
...
... bekomme dann aber die Fehlermedung

Code: Alles auswählen

    form.fields('auswahl').choices = [('1', 'eins'), ('2', "Zwei")]
TypeError: 'dict' object is not callable
Diese Meldung kenne ich schon von den Versuchen die obengenannten Vorschläge die ich in stackoverflow gefunden habe umzusetzen. Was mache ich falsch?
Korrekt - die Fehlermeldung sagt dir ja auch klar, was die falsch machst bzw. falsch abgeschrieben hast. `form.fields` ist ein Dictionary, der Zugriff auf Schlüssel darin erfolgt - wie jeder Index-Zugriff in Python - mit _eckigen_ Klammer. Runde Klammern wären ein Funktionsaufruf, nur ist `form.fields` nicht "callable", weil Dicts nicht "callable" sind. Sagt ja auch die Fehlermeldung.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Oh Mann! Noch schlimmer als schwer von Begriff ist schwer von Begriff und schlampig!
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

noisefloor hat geschrieben: Donnerstag 30. Januar 2025, 17:42 Was anderes mache ich in der Shell-Session auch nicht, nur halt als Ausgabe in die Konsole.
Also wenn ich das mit der eckigen Klammer ändere, dann ist auch die Fehlermeldung weg. Aber durch den Rest muss ich mich noch durcharbeiten. Wenn ich deine Anmerkung oben richtig verstehe, dann hast du den geposteten Code in der shell getestet - wie macht man das?

Mit

Code: Alles auswählen

>>> task.fields['select_task'].choices = [('3', 'foo'), ('4', 'spam')]
dachte ich, überschreibst du die Optionen, die in der Form voreingestellt sind, aber hier werden sie nochmals geändert

Code: Alles auswählen

 <option value="3">foo</option>\n\n  <option value="4">spam</option>
?

... und

Code: Alles auswählen

form.as_p()
kommt doch in mein Template?
Benutzeravatar
noisefloor
User
Beiträge: 4172
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Pitwheazle hat geschrieben: Donnerstag 30. Januar 2025, 18:28 Wenn ich deine Anmerkung oben richtig verstehe, dann hast du den geposteten Code in der shell getestet - wie macht man das?
Ins Django Projekt wechseln und in dem Verzeichnis, wo deine manage.py liegt `python manage.py shell` aufrufen. Dann wird der Python Interpreter gestartet und die Einstellungen für dein Projekt geladen. Du könntest dann in der Shell z.B. auch deine Models oder Forms importieren. Siehe auch z.B. https://docs.djangoproject.com/en/5.1/i ... th-the-api und https://www.nickmccullum.com/useful-fea ... ngo-shell/.
Pitwheazle hat geschrieben: Donnerstag 30. Januar 2025, 18:28 Mit

Code: Alles auswählen

>>> task.fields['select_task'].choices = [('3', 'foo'), ('4', 'spam')]
dachte ich, überschreibst du die Optionen, die in der Form voreingestellt sind, aber hier werden sie nochmals geändert

Code: Alles auswählen

 <option value="3">foo</option>\n\n  <option value="4">spam</option>
Nee, Überschreiben ist schon richtig. Das 2. ist "nur" die HTML-Ausgabe der gerenderte Form.
Pitwheazle hat geschrieben: Donnerstag 30. Januar 2025, 18:28

Code: Alles auswählen

form.as_p()
kommt doch in mein Template?
Ja. Aber `form.as_p()` ist am Ende ja nur der Aufruf der Methode `as_p` von `form`, was wiederum die Instanz einer Klasse ist. Das ist am Ende alles nur normales Python. Den Methodenaufruf kannst du halt überall machen und die Methode liefert dann halt einen String zurück, der HTML ist. Wenn man das im Template hat, dann wird es ins Template eingebaut. Du kannst die Methode aber grundsätzlich auch wo anders im Code aufrufen und dann mit dem String machen, was du willst.

Wenn man mit Django arbeitet ist es _sehr_ hilfreich, wenn man das in Python mit Klassen, Methoden, Instanzen, Funktionen etc. grundlegend verstanden hat. Weil das halt vieles vom Verständnis einfacher macht. Falls du in deinem Projekt mal anfangen solltest, Class-Based Views (CBV) statt Function-Based Views (FBV) zu nutzen, wird das noch viel wichtiger. Weil man früher oder später an den Punkt kommt, wo man im CBV nicht nur Attribute überschreibt, sondern auch Methoden.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Ich muss mich wiedrmal für deine grenzenlose Geduld bedanken.
noisefloor hat geschrieben: Donnerstag 30. Januar 2025, 20:45 Ins Django Projekt wechseln und in dem Verzeichnis, wo deine manage.py liegt `python manage.py shell` aufrufen.
Das wusste ich eigentlich und habe es auch schon verwendet - aber immer nur für eine Zeile. Ich vermute, du schaffst das aber mit einem mehrzeiligen Code.
.... wenn du das jetzt so sagst, vermute ich auch, dass das was unten hinter dem ' steht, die Ausgabe vom Interpreter ist. Das hätte ich vielleicht auch schon merken müssen :s.
noisefloor hat geschrieben: Donnerstag 30. Januar 2025, 20:45 Wenn man mit Django arbeitet ist es _sehr_ hilfreich, wenn man das in Python mit Klassen, Methoden, Instanzen, Funktionen etc. grundlegend verstanden hat. Weil das halt vieles vom Verständnis einfacher macht.
Da hast du mich aber erwischt! Glaube mir, ich habe mir große Mühe gegeben, das zu verstehen und habe ein Buch zu objektorientiertem Programmieren durchgearbeitet und mich auch durch entsprechende Erklärungen im Internet durchgearbeitet. Wenn ich das so lese verstehe ich das auch mit den Autos und dass es PKWs und LKWs gibt und die verschiedene Farben haben .... ich habe aber noch keinen Anknüpfungspunkt gefunden, wie ich das grundlegend in meinem Projekt anwenden kann ... und ich fürchte, dass schafft mein altes Hirn auch nicht mehr. Ich hoffe ich kann mich weiter mit meinen Funktionen durchmogeln. Ich behalte das aber immer noch im Auge (ohne viel Hoffnung).
Benutzeravatar
noisefloor
User
Beiträge: 4172
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ich vermute, du schaffst das aber mit einem mehrzeiligen Code.
Das ist der ganz normaler Python-Interpreter mit dem normalen REPL Verhalten des interaktiven Python-Intepreters. Das ist das selbe wie der Aufruf von `python` im Terminal. Nur das bei `python manage.py shell` noch Daten aus deinem Projekt zugänglich / importierbar sind.

Django ist IMHO ganz gut dafür, ein besseres "real world" Verständnis zu entwickeln. Selbst wenn man "nur" FBV verwendet (was je nach Anwendungsfall auch der bessere Weg ist), dann ist jedes Modell, dass du definierst, eine Klasse und jede Form. Plus diverse andere Sachen. Wenn du im interaktiven Interpreter bis un ein Klasse instanzierst wie oben z.B. `task = Tasks()`, kann man sich anschließend mit `dir(task)` alle Methoden und Attribute anschauen. Falls du `dir` ncht kennst: das funktioniert mit allen Objekten, das ist nicht auf Klassen beschränkt.

Gruß, noisefloor
Antworten