Auswahl bedingt anzeigen

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

... und dann habe ich noch ein Problem bei dem mein armes Hirn einfach überfordert ist:
Bei einigen der Aufgaben können die Schüler, je nach Jahrgang ("jg") oder Lernfortschritt ("stufe"), verschiedene Optionen wählen. Bei meinen aktuellen Aufgaben zur Prozentrechnung sieht das z.B. so aus:
Bild
Ob diese Optionen zur Auswahl angezeigt werden, stelle ich hier ein:
Bild
Das funktioniert auch bedingt: sobald die Kids im Jahrgang 9 sind oder die Stufe 28 erreicht haben, werden diese Optionen nicht mehr angezeigt, vorher schon - und zwar alle. Ich möchte erreichen, dass z.B. ab Stufe 18 die erste Option ("Berechnug des Prozentwertes") nicht mehr angezeigt wird, da die Kids ab dieser Stufe den sowieso ausrechnen müssen und dass ab Jahrgang 8 nur noch die letzte Option ("mit Zinsrechnung") angezeigt wird, den Rest müssen sie sowieso rechnen. Zurzeit werden aber entweder alle vier angezeigt oder das entsprechende Template wird gar nicht aufgerufen.
Das template "optionen":

Code: Alles auswählen

<h2>{{ kategorie.name }}</h2>
<ul>    
<form action="{% url 'optionen' kategorie.slug %}" method="Post">
    {% csrf_token %}
    {{auswahl_form}}
    <input type="submit" value="weiter">
</form>
</ul>
die form ""auswahl_form":

Code: Alles auswählen

class AuswahlForm(forms.Form):
    optionen=forms.ModelMultipleChoiceField(queryset=Kategorie.objects, widget=forms.CheckboxSelectMultiple, required=False)
    def __init__(self, *args, **kwargs):
        kategorie = kwargs.pop('kategorie')
        super().__init__(*args, **kwargs)
        self.fields['optionen'].queryset = kategorie.auswahl_set.all()
der/die/das view "optionen":

Code: Alles auswählen

#Hier können u.U. Optionen gewählt werden - z:B. ob mit oder ohen Kommazahlen gerechnet wird
def optionen(req, slug):
    kategorie = get_object_or_404(Kategorie, slug = slug)
    form = AuswahlForm(kategorie = kategorie)
    user = get_user(req.user)   
    zaehler = get_object_or_404(Zaehler, kategorie = kategorie, user = user)
    if req.method == 'POST':
        form = AuswahlForm(req.POST, kategorie = kategorie)
        if form.is_valid():
            optionen_text = ';'.join(map(str, form.cleaned_data['optionen']))
            if optionen_text == "":
                optionen_text = "keine"
        else:
            optionen_text = "keine"  
    else:
        anzahl = kategorie.auswahl_set.all().count()
        if anzahl>0:
            anzahl = Auswahl.objects.filter(bis_jg__gte = user.jg, bis_stufe__gte = user.stufe, kategorie = kategorie).count()
            if anzahl>0:
                return render(req, 'core/optionen.html', {'kategorie': kategorie, 'auswahl_form':form})
            else:
                optionen_text = "keine"    
        else:
            optionen_text = "keine"
    zaehler.optionen_text = optionen_text       
    zaehler.save()
    typ_anf, typ_end = aufgaben(kategorie.zeile, jg = user.jg, stufe = user.stufe, optionen = zaehler.optionen_text)
    zaehler.typ_anf = typ_anf
    zaehler.typ_end = typ_end
    zaehler.save()
    return redirect('main', slug)
... dass das überhaupt funktioniert ist für mich ein Wunder. Ich glaube, bei der Konstruktion habt ihr mir schon mal geholfen.
Wenn ich das richtig sehe, überprüft der Code:

Code: Alles auswählen

            anzahl = Auswahl.objects.filter(bis_jg__gte = user.jg, bis_stufe__gte = user.stufe, kategorie = kategorie).count()
            if anzahl>0:
                return render(req, 'core/optionen.html', {'kategorie': kategorie, 'auswahl_form':form})
ob für denjenigen Schüler Optionen zutreffen und zeigt dann halt alle - oder gar keine. Kann man das ändern? Unter Umständen wäre es ja auch schon hilfreich, wenn die für den/die Schüler/in nicht relevanten Optionen schon ausgewählt wären - ohne dass die Auswahl entfernt werden kann.
Benutzeravatar
sparrow
User
Beiträge: 4361
Registriert: Freitag 17. April 2009, 10:28

Diese Zeile Code:

Code: Alles auswählen

self.fields['optionen'].queryset = kategorie.auswahl_set.all()
sorgt, wenn ich das richtig sehe, dafür, dass alle Optionen im Form eingefügt werden.
Du willst die aber Filter. Das musst du tun, statt .all() zu verwenden.
Pitwheazle
User
Beiträge: 978
Registriert: Sonntag 19. September 2021, 09:40

Wenn ich jetzt noch wüsste was ich da gemacht habe ...
Also ich glaube, die Zeile

Code: Alles auswählen

        anzahl = kategorie.auswahl_set.all().count()
        if anzahl>0:
überprüft zunächst mal, ob es in dieser Kategorie überhaupt Optionen gibt (es existieren nämlich auch Kategorien in denen keine Optionen vorhanden sind) ich glaube mich zu erinnern, dass ich damit einen Fehler abgefangen habe - und erst:

Code: Alles auswählen

            anzahl = Auswahl.objects.filter(bis_jg__gte = user.jg, bis_stufe__gte = user.stufe, kategorie = kategorie).count()
            if anzahl>0:
setzt dann den Filter. Nehmen wir an ein user ist in Stufe 27 und im Jahrgang 8 - dann trifft der Filter für ihn zu, die letzte Option sollte also angezeigt werden. Es wird aber das template angezeigt, mit allen Optionen, das wird ja, soweit ich meinen Code verstehe, ja auch nicht anders erwartet.
Benutzeravatar
sparrow
User
Beiträge: 4361
Registriert: Freitag 17. April 2009, 10:28

Da prüfst du aber nur die Anzahl ( .count() ).
Aber in der Form nimmst du trotzdem alle Optionen ohne Einschänkung durch einen Filter.
Pitwheazle
User
Beiträge: 978
Registriert: Sonntag 19. September 2021, 09:40

sparrow hat geschrieben: Sonntag 25. Juni 2023, 17:47 Da prüfst du aber nur die Anzahl ( .count() ).
Aber in der Form nimmst du trotzdem alle Optionen ohne Einschänkung durch einen Filter.
genau! Ich habe mal wieder keine Ahnung, wie ich das filtern kann - oder besser gesagt (ich habe ja einen Filter) wie ich den Filter im template bzw. in der form anwenden kann.
Pitwheazle
User
Beiträge: 978
Registriert: Sonntag 19. September 2021, 09:40

sparrow hat geschrieben: Sonntag 25. Juni 2023, 17:21 Diese Zeile Code:

Code: Alles auswählen

self.fields['optionen'].queryset = kategorie.auswahl_set.all()
sorgt, wenn ich das richtig sehe, dafür, dass alle Optionen im Form eingefügt werden.
Du willst die aber Filter. Das musst du tun, statt .all() zu verwenden.
An dieser Baustelle bin ich auch noch. manchmal hilft es Probleme etwas ruhen zu lassen um klarer zu sehen. Genau hier, bei .all() liegt das Problem. Kannst du mir auch hier einen Tip geben, wie ein Filter anstelle von .all() aussehen könnte - und unter Umständen, wie ich diesem Werte aus dem view übergeben kann?
Pitwheazle
User
Beiträge: 978
Registriert: Sonntag 19. September 2021, 09:40

Dieses Problem habe ich immer noch nicht gelöst. Mit Rumprobieren bin ich jetzt aber etwas weiterbekommen. Anstelle von

Code: Alles auswählen

self.fields['optionen'].queryset = kategorie.auswahl_set.all()
habe ich jetzt den Code:

Code: Alles auswählen

self.fields['optionen'].queryset = kategorie.auswahl_set.all().filter(bis_jg__gte=8)
ausprobiert und ich bekomme nur noch die eine Option für Jahrgang 8 angezeigt. Wenn ihr mir jetzt einen Tipp geben könntet, wie ich das mit dem Jahrgang des jeweiligen users vergleichen kann, schaffe ich vielleicht auch den Rest.
Die Form wird hier im View aufgerufen:

Code: Alles auswählen

def optionen(req, slug):
    kategorie = get_object_or_404(Kategorie, slug = slug)
    form = AuswahlForm(kategorie = kategorie)
    user = get_user(req.user) 
    print(user.jg)  
    zaehler = get_object_or_404(Zaehler, kategorie = kategorie, user = user)
    if req.method == 'POST':
        form = AuswahlForm(req.POST, kategorie = kategorie, user = user)
        if form.is_valid():
            optionen_text = ';'.join(map(str, form.cleaned_data['optionen']))
            ...
hier bekomme ich bei print(jg.user) auch den Jahrgang angezeigt und gehe davon aus. dass er auch an die form weitergegeben wird - wie greife ich aber darauf zu

Code: Alles auswählen

filter(bis_jg__lte=user_jg)
geht nicht.
Antworten