Hintergrundfarbe in Formularen ändern

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

Ich habe da wieder mal was zusammengepfuscht (weil ich es nicht besser kann), was mir so nicht gefällt. Am besten kann ich das mit einem Screenshot erklären (Sorry):
Bild
Also die Kids müssen eine Wertetabelle ausfüllen und ich muss feststellen, wieviele Einträge richti, falsch und leer sind ... und dies natürlich auch rückmelden. Ich habe da ein hochkompliziertes Kostrukt mit Primzahlen erstellt (das ich auch nur schwierig nachvollziehen kann, das aber soweit funktioniert. Die Nutzer bekommen eine Meldung wie z.B. dieser "2. Eintrag falsch 3. Eintrag falsch 4. Eintrag falsch 5. Eintrag leer ". Ich möchte aber gerne die Felder in denen die Eingabe richtig, falsch oder leer ist einfärben, habe aber keine Ahnung, ob das überhaupt geht.
Ich stelle hier mal die entsprechenden teile des Codes ein (bitte nicht erschrecken).
Also der Teil aus dem Template:

Code: Alles auswählen

...<tr>
    <td>{{parameter.x0}}</td>
    <td>{{form.y0}}</td>                                                                    
</tr>
<tr>
    <td>{{parameter.x1}}</td>
    <td>{{form.y1}}</td>...     
die forms:

Code: Alles auswählen

class AufgabeFormTerm(forms.Form):
    y0 = forms.DecimalField(label='', max_digits=5,
                                decimal_places=2, required=False, localize=True, widget=forms.TextInput(attrs={'size': 3, 'autocomplete': 'off', 'autofocus': True,}))
    y1 = forms.DecimalField(label='', max_digits=5,
                                decimal_places=2, required=False, localize=True, widget=forms.TextInput(attrs={'size': 3, 'autocomplete': 'off'}))...
den Teil aus der Auswertung:

Code: Alles auswählen

        if isinstance(eingabe, list):                           # für Wertetabellen
            lsg = lsg[0]
            punkte = 0
            rueckmeldung = ""
            primzahlen = [3,5,7,11,13]
            for n in range(len(lsg)):
                print(eingabe[n])
                if not eingabe[n] is None:                      # überprüft ob Einträge richtig sind
                    if (float(lsg[n].replace(",", "."))) == float(eingabe[n]):
                        punkte += primzahlen[n]
                    else:
                        rueckmeldung = rueckmeldung + (str(n+1) + ". Eintrag falsch ")
                else:
                    rueckmeldung = rueckmeldung + (str(n+1) + ". Eintrag leer ")
            return punkte, rueckmeldung
(Mit den Primzahlen kann ich feststellen, welche Punkte es für richtige und falsche Eingaben gibt. Bei drei Werten bei den Wertetabellen für Zuordnungen ging das noch, jetzt habe ich Tabellen mit fünf Werten ...)
Wenn mir jemand sagen kann, ob ich hier überhaupt eine Rückgabe an die Forms hinbekommen kann und wie man die Hintergrundfarbe anspricht, könntee ich mich schon mal weiter in meinen Code reinarbeiten...
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Aus den paar Fragmenten, die Du da präsentierst, kann man mal wieder nichts rauslesen, und muß sich den Rest erst mühselig selbst programmieren, um es nachvollziehen zu können. Und das was dann rauskommt, ist bestimmt nicht das, was Du geschrieben hast, und dann kommt es wieder zu Mißverständnissen.
Also zeige den kompletten relevanten Code, also das ganze Template, soweit es nötig ist, die gesamte Funktion zur Route, etc.

Aus den Fragmenten läßt sich schonmal rauslesen, dass da einiges falsch ist. Statt mehrere Wörterbücher parameter und form (und noch ein drittes mit der Zellenfarbe), in dem dann auch noch durchnummerierte Schlüssel stecken, benutzt man eine Liste, in der alle drei Angaben in einem Wörterbuch stecken.

Eine isinstance-Prüfung ist ein deutliches Zeichen dafür, dass Du hier auch etwas falsch machst, warum weißt Du nicht, dass die Eingabe eine Liste ist?
Man benutzt keine kryptischen Abkürzungen, weder jg für jahrgang noch lsg für loesung.
Und warum ist lsg eine Liste mit nur einem Eintrag? Man recyclt auch keine Namen, weil lsg als Liste etwas anderes ist als lsg, was diese eine Element dann ist.
Über einen Index iteriert man nicht. Man vergleicht mit ›is not None‹ und nicht ›not x is None‹.
Für das Umwandeln einer Kommazahl solltest Du eine eigene Funktion haben, statt an allen möglichen Stellen explizit ein replace hinzukopieren.
Man stückelt auch keine Strings mit + zusammen.

Das ganze sähe dann so aus:

Code: Alles auswählen

ergebnis = []
for zeile in wertetabelle:
    if not zeile['eingabe']:
        status = "leer"
    elif to_float(zeile['eingabe']) == zeile['loesung']:
        status = "richtig"
    else:
        status = "falsch"
    ergebnis.append(dict(zeile, status=status))

Code: Alles auswählen

<table>
  <thead><tr><th>x</th><th>{{formel}}</th></tr></thead>
  <tbody>
    {% for zeile in wertetabelle %} 
    <tr>
        <td>{{zeile['x_wert']}}</td>
        <td class="{{zeile['status']}}">{{zeile['eingabe']}}</td>
    </tr>
    {% endfor %} 
  </tbody>
</table>
Bei so einem umfangreichen Projekt, wie Du es hast, lohnt sich der Aufwand, einmal ordentlich Python zu lernen.
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Bei so einem umfangreichen Projekt, wie Du es hast, lohnt sich der Aufwand, einmal ordentlich Python zu lernen.
Dank eurer Hilfe, komme ich da immer weiter. ich habe aber schon darauf hingewiesen, dass meine Konzentrationfähigkeits da begrenzt ist. Ich muss mir die Zusammenhänge immer wieder neu zusammenbasteln und bei den komplexeren Teilen bin ich überfordert.
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Eine isinstance-Prüfung ist ein deutliches Zeichen dafür, dass Du hier auch etwas falsch machst, warum weißt Du nicht, dass die Eingabe eine Liste ist?
...
Und warum ist lsg eine Liste mit nur einem Eintrag?
Nun ja, meine Aufgaben sind ziemlich unterschiedlich. Oft ist einfach eine einzige Zahl die richtige Lösung, oft gibt es mehrere richtige Lösungen. Da überprüfe ich diese der Reihe nach mit denen, die ich in der Variablen "Lösungen" speichere. Wenn der User allerdings auf "Lösung anzeigen" klickt, bekommt er immer die erste in der jeweiligen Liste. Manchmal ist es so, dass es richtige Lösungen gibt und Antworten, bei denen ich nicht die volle Punktzahl gebe und u.U. einen Kommentar ausgebe - das ist bei verschiedenen Kategorien unterschiedlich. Eine Besonderheit sind die Wertetabellen, hier speichere ich eine Liste der drei, bzw. fünf richtigen Antworten als ersten (und einzigen ) Eintrag in der "Löungs"liste und ob eine Wertetabelle vorliegt, erkenne ich daran, dass ich überprüfe, ob der erste Eintrag in dieser Liste wiederum eine Liste ist.
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Aus den Fragmenten läßt sich schonmal rauslesen, dass da einiges falsch ist. Statt mehrere Wörterbücher parameter und form (und noch ein drittes mit der Zellenfarbe), in dem dann auch noch durchnummerierte Schlüssel stecken, benutzt man eine Liste, in der alle drei Angaben in einem Wörterbuch stecken.
Das ist sehr hilfreich und das werde ich einarbeiten ... und hoffentlich irgendwann lernen.
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Über einen Index iteriert man nicht.
OK - warum nicht - wie sonst?
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Das ganze sähe dann so aus:

Code: Alles auswählen

        <td class="{{zeile['status']}}">{{zeile['eingabe']}}</td>
Ich weiß es sehr zu schätzen, dass du mir diesen Code trotz meiner mangelnden Vorgaben zusammengebastlt hast. Mir fehlt jetzt aber noch der entscheidende Teil: Wie färbe ich mit 'status' meinen Hintergrund?
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Also zeige den kompletten relevanten Code, also das ganze Template, soweit es nötig ist, die gesamte Funktion zur Route, etc.
Das traue ich mich einfach nicht. Ich habe Angst, dass ihr mich aus diesem Forum ausschließt, wenn ihr den seht. Und es fällt mir auch ziemlich schwer, den Teil zu finden, der "relevant" ist. Willst du dir das wirklich antun?
paddie
User
Beiträge: 101
Registriert: Donnerstag 11. Oktober 2018, 18:09

Du mußt jetzt in deinem CSS-File für die Klasse 'status' etwas in der Art wie

Code: Alles auswählen

.richtig {
    background:	green;
}

.falsch{
    background:	red; 
}

einsetzen
Anstatt der Farbnamen kannst du natürlich auch den gewünschten Farbcode eingeben.
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,
Pitwheazle hat geschrieben: Mittwoch 29. November 2023, 21:50
Das ist sehr hilfreich und das werde ich einarbeiten ... und hoffentlich irgendwann lernen.
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Über einen Index iteriert man nicht.
OK - warum nicht - wie sonst?
Das ist im Beispielcode schon gezeigt, schau dir mal deine 'for'-Schleife an:

Code: Alles auswählen

for n in range(len(lsg)):
und jetzt die Schleife von @Sirius3:

Code: Alles auswählen

for zeile in wertetabelle:
Man kann so direkt auf das Objekt zugreifen, anstatt den Umweg über den Index zu gehen.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

paddie hat geschrieben: Donnerstag 30. November 2023, 07:51 Du mußt jetzt in deinem CSS-File für die Klasse 'status' etwas in der Art wie

Code: Alles auswählen

.richtig {
    background:	green;
}

.falsch{
    background:	red; 
}

einsetzen
Anstatt der Farbnamen kannst du natürlich auch den gewünschten Farbcode eingeben.
Danke, funktioniert. Färbt zwar nicht das Formular sondern einen Rahmen drumrum - ist aber prima so! Ich hatte das so auch schon mal ohne Erfolg ausprobiert. Ich dachte, ich hätte was falsch gemacht, hätte aber wahrscheinlich, wie jetzt auch, den Cache leeren müssen.
Dennis89 hat geschrieben: Donnerstag 30. November 2023, 08:23 Hallo,
....
Man kann so direkt auf das Objekt zugreifen, anstatt den Umweg über den Index zu gehen.
Grüße
Dennis
... da sieht man mal wieder die Demenz: Das habe ich doch selbst an anderen Stellen auch schon so gemacht.
Sirius3 hat geschrieben: Mittwoch 29. November 2023, 20:19 Das ganze sähe dann so aus:

Code: Alles auswählen

ergebnis = []
for zeile in wertetabelle:
    if not zeile['eingabe']:
        status = "leer"
    elif to_float(zeile['eingabe']) == zeile['loesung']:
        status = "richtig"
    else:
        status = "falsch"
    ergebnis.append(dict(zeile, status=status))

Code: Alles auswählen

<table>
  <thead><tr><th>x</th><th>{{formel}}</th></tr></thead>
  <tbody>
    {% for zeile in wertetabelle %} 
    <tr>
        <td>{{zeile['x_wert']}}</td>
        <td class="{{zeile['status']}}">{{zeile['eingabe']}}</td>
    </tr>
    {% endfor %} 
  </tbody>
</table>
Das sieht prima aus und ich habe versucht, das einzubauen, habe es aber noch nicht geschafft. Wie bekomme ich die Eingaben im template in den View?
Dazu habe ich bisher, wie oben beschrieben, Formulare benutzt (weil ich es bisher nicht besser kann - geht das auch anders?):
im Template steht:

Code: Alles auswählen

    <form action="{% url 'main' kategorie.slug %}" method="post">
        {% csrf_token %}
        {% if "tab" in parameter.name %}
            <fieldset>
            <table>
                <th>{{parameter.titel_x}}</th>
                <th>{{parameter.titel_y}}</th>

                {% if lsg %}
                    <tr>
                        <td>{{parameter.x0}}</td>
                        <td>{{parameter.y0}}</td>                                                                       
                    </tr>
                    <tr>
                        <td>{{parameter.x1}}</td>
                        <td>{{parameter.y1}}</td>                                                                    
                    </tr>
                    <tr>
                        <td>{{parameter.x2}}</td>
                        <td>{{parameter.y2}}</td>                                                                    
                    </tr>
                    <tr>
                        <td>{{parameter.x3}}</td>
                        <td>{{parameter.y3}}</td>                                                                    
                    </tr>                                    
                    <tr>
                        <td>{{parameter.x4}}</td>
                        <td>{{parameter.y4}}</td>                                                                    
                    </tr>
                    <tr>
                        <td>{{parameter.x5}}</td>
                        <td>{{parameter.y5}}</td>                                                                    
                    </tr>

                {% else %}
                    {% if "term" in parameter.name %}
                        <tr>
                            <td>{{parameter.x0}}</td>
                            <td>{{form.y0}}</td>                                                                    
                        </tr>
                        <tr>
                            <td>{{parameter.x1}}</td>
                            <td>{{form.y1}}</td>                                                                    
                        </tr> 
                    {% else %}
                        <tr>
                            <td>{{parameter.x0}}</td>
                            <td>{{parameter.y0}}</td>                                                                       
                        </tr>
                        <tr>
                            <td>{{parameter.x1}}</td>
                            <td>{{parameter.y1}}</td>                                                                    
                        </tr>
                    {% endif %}
                    <tr>
                        <td>{{parameter.x2}}</td>
                        <td>{{form.y2}}</td>                                                                    
                    </tr>
                    <tr>
                        <td>{{parameter.x3}}</td>
                        <td>{{form.y3}}</td>                                                                    
                    </tr>                                    
                    <tr>
                        <td>{{parameter.x4}}</td>
                        <td>{{form.y4}}</td>                                                                    
                    </tr> 
                        <tr>
                        <td>{{parameter.x5}}</td>
                        <td>{{form.y5}}</td>                                                                    
                    </tr>                               
                {%endif%}                                   
            </table>
und im View:

Code: Alles auswählen

    if "tab" in protokoll.parameter["name"]:                            # für Wertetabellen
        eingabe = []
        if "term" in protokoll.parameter["name"]:                            # für Terme
            eingabe.append(form.cleaned_data['y0'])
            eingabe.append(form.cleaned_data['y1'])
        eingabe.append(form.cleaned_data['y2'])
        eingabe.append(form.cleaned_data['y3'])
        eingabe.append(form.cleaned_data['y4'])
... ich habe also einmal eine Version, wenn die Lösung angezeigt wird und einmal eine Version mit Eingabefeldern. Bei dir sieht das so aus, als könnte man das in einem machen?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei einem so großen Projekt, wie Du es hast, lohnt es sich wirklich, sich mal in CSS einzuarbeiten. Das C steht für kaskadiert: Wenn Du also eine Klasse td.leer hast, kannst Du damit auch das Eingabefeld stylen: `td.leer input`.

Deine if-Abfragen in parameter.name sind falsch. Man kodiert nicht Informationen in einen Namen hinein. Und genauso nummeriert man keine Attribute durch, wenn man eigentlich Listen benutzen will.
Ich kenne mich mit Django-Forms nicht aus, aber wenn die keine Listen unterstützen, ist vielleicht die Verwendung von Forms hier nicht das richtige, weil Du ja von deren Unterstützung eh nichts nutzt.

In Deinem Template fehlt <tr> um die Headerzeile, und korrekterweise würde man das in thead und den Rest in tbody packen, wie ich das ja schon in meinem Beispiel getan habe.
Wenn Du je nach Fall unterschiedliche Anzeigen haben möchtest, dann kodiert man das in die `parameter` (was ein bescheuerter Name ist für eine Aufgabe vom Typ Wertetabelle)

Code: Alles auswählen

<table>
  <thead><tr><th>{{aufgabe.title_x}}</th><th>{{aufgabe.title_y}}</th></tr></thead>
  <tbody>
    {% for zeile in aufgabe.wertetabelle %} 
    <tr>
        <td>{{zeile['x_wert']}}</td>
        <td class="{{zeile['status']}}">{%if zeile['mode'] == 'show_solution'%}{{zeile['loesung']}}{%else%}<input name="y-wert" type="number" value="{{zeile['eingabe']}}">{%endif%}</td>
    </tr>
    {% endfor %} 
  </tbody>
</table>
Dann brauchst Du nämlich nur noch im Python-Code eine Fallunterscheidung, was den Code viel fehlertoleranter macht.
Pitwheazle
User
Beiträge: 873
Registriert: Sonntag 19. September 2021, 09:40

Danke - ich habe es hinbekommen!
Antworten