Ist Django für mein Projekt geeignet?

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

Hallo Whitie,
langsam klappt das eine oder andere auch wenn ich alleine nur genug rumprobiere.
Vielleicht kannst du mir hier wieder helfen:
Du hast den Grundstock für das ganze Projekt gelegt (ohne diesen Code hätte ich das nie hinbekommen).
Auf der ersten Seite werden alle Kategorien aufgezeigt. Dein Code:

Code: Alles auswählen

    {% for modul in module %}
        <li><a  class="button" href="{% url 'main' modul.slug %}" {% if not modul.fragen.count %}disabled{% endif %}>
            {{ modul.name }}</a></li>
    {% endfor %}
Ich gehe davon aus, dass "disabled" dafür sorgen müsste, dass die entsprechende Kategorie nicht anwählbar ist, wenn keine Fragen dazu da sind - das klappt aber nicht. Ich kann Kategorien auch anwählen, wenn keine Fragen dazu gespeichert sind und bekomme dann natürlich die Fehlermeldung, dass der entsprechende view fehlt (weil ich noch nicht geschrieben habe). Was stimmt nicht? Brauchst du dafür noch Code? (Das funktionierte in deinem Beispiel m.E. auch schon nicht - möglicherweise habe ich das ja aber auch nicht richtig verstanden)
Grüße
Pit
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Hallo Pit,
das kann sein, dass man einen Link gar nicht "disabled" darstellen kann. Habe ich nicht drauf geachtet. Ich würde es dann evtl. so machen:

Code: Alles auswählen

{% for modul in module %}
<li>
    {% if modul.fragen.count %}
    <a  class="button" href="{% url 'main' modul.slug %}">{{ modul.name }}</a>
    {% else %}
    <button class="button" disabled>{{ modul.name }}</button>
    {% endif %}
</li>
{% endfor %}
Viele Grüße
Whitie
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Prima, wieder was gelernt, das kann ich auch anderswo gebrauchen.

Aber mal was anderes:
Woher kannst du das?
Studium? Tutorium durchgearbeitet? Machst du das beruflich?
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Ich hab mir das selbst erarbeitet. Angefangen habe ich ähnlich wie du. Ich hatte vor langer Zeit (~20 Jahren) mal eine Notenliste in Excel für die Arbeit gemacht und diverse Zusatzfunktionen haben mich ans Limit meiner VBA Kenntnisse gebracht. Privat hatte ich zu dieser Zeit etwas mit PHP rumgespielt, so wie fast jeder mal (grausamer Code direkt in HTML, usw.).

Daraus ist die Idee entsprungen, die Notenliste als echte Desktopanwendung umzusetzen, die ich dann komplett individuell gestalten kann. Hab mir dann erstmal PHP-Gtk angesehen, aber schnell verworfen. PHP sollte im Web bleiben ;-) So bin ich dann irgendwie zu Python gekommen. Am Anfang habe ich mit wxWigets experimentiert, bin aber recht schnell zu PyQt gewechselt. Ist viel angenehmer. Irgendwann später ist dann alles mehr und mehr ins Web gewandert, da habe ich Django gefunden (vorher noch Turbogears und Pylons).

Ich kann vieles während meiner Arbeitszeit machen, ist aber eigentlich nicht mein Job. Ich bin Industriemeister Pharmazie und hab in der Richtung auch ausgebildet. Vor 5 Jahren ist dann unser Admin & EDV-Dozent in Rente gegangen und wir haben keinen Nachfolger gefunden. Wir hatten nur Leute die super Admins waren, aber keinem was beibringen konnten oder anders rum. Da habe ich den Bereich gewechselt. Und jetzt sind wir, auch dank der Pandemie, soweit, dass wir einen externen EDV-Dozenten angeheuert haben (ab September). Ich bin mit Admin-Tätigkeit + Pflege meiner Software ausgelastet. Damit ist es dann mein Job ;-)

Viele Grüße
Whitie

P. S. Funfact: Die Notenliste ist immer noch Excel. Ich werde das jetzt aber angehen und in unsere (Django-) Azubiverwaltung integrieren.

Edit: Ich bin hier auch regelmäßig beeindruckt von Lösungen, die die Experten hinzaubern. Da fehlt mir oft der Informatik Hintergrund. Ich hab mal im Schuljahr 91/92 eine Verwaltungssoftware für unsere Schulbücherei in Turbo Pascal geschrieben (mit dem ganzen Kurs). Danach dann ~8 Jahre gar nicht mehr programmiert.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Whitie hat geschrieben: Freitag 8. April 2022, 18:18 Ich hab mir das selbst erarbeitet. Angefangen habe ich ähnlich wie du.
... du meinst, ich könnte das auch noch schaffen? Ich bin da skeptisch. Bei komplexeren Zusammenhängen verliere ich immer wieder den Überblick und ich habe mich auch immer noch nicht drangetraut, eine Klasse zu programmieren. Ich hatte ja weiter oben schon geschrieben, wie ich stattdessen die einzelnen Funktionen der Aufgabenkategorien nutzen will, indem ich verschiedene Paramenter übergebe. Da komme ich gerade wieder nicht so recht weiter. Ich versuche es nochmal zu beschreiben:

Die Funktion, die du in deinem view "challenge()" genannt hast, heißt jetzt bei mir "main()" weil da immer alles zusammenläuft. Die Kontrolle, ob eine Aufgabe richtig oder falsch ist nach (if req.method == 'POST':) funktioniert soweit. Ansonsten (else) wird eine neue Aufgabe erstellt. Bevor das passiert rufe ich jetzt eine Funktion auf, die, wenn vorhanden, eine Seite mit den Optionen einblendet.und die, eventuell, gewählten Optionen zurückmeldet. Das sieht etwa so aus:

Code: Alles auswählen

    else:
        frage = Frage.objects.filter(kategorie=modul).order_by('?').first()
        frage_id=frage.id
        form = AufgabeFormZahl()
        user=get_fake_user()
        if zaehler.optionen=="":
            return redirect('optionen', slug)
*************            
            typ_anf, typ_end = aufgaben(modul.id, jg=user.jahrgang, stufe=user.stufe, typ_anf=0, typ_end=0, optionen='wahl')
**************
        typ, zahl1, zahl2, result =aufgaben(modul.id, jg=user.jahrgang, stufe=user.stufe, typ_anf=typ_anf, typ_end=typ_end) 
 
Vor der ersten Sternchenreihe wird die Seite aufgerufen, auf der die Optionen angekreuzt werden können (das funktioniert) und die Auswahl wird hier auch brav unter "zaehler.optinen" abgespeichert:

Code: Alles auswählen

def optionen(req, slug):
    kategorie = get_object_or_404(Kategorie, slug=slug)
    form = AuswahlForm(kategorie=kategorie)
    user=get_fake_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():
            zaehler.optionen = ';'.join(map(str, form.cleaned_data['optionen']))
            zaehler.save
            return HttpResponse(zaehler.optionen)
... und nach der ersten Sternchenzeihe möcte ich jetzt den Inhalt von "zaehler.optionen" weitergeben wo jetzt "optionen='wahl' steht. Daraufhin würde in der Funktion "addieren" festgelegt in welchem Bereich die Aufgaben erstellt werden (typ_anf bis typ_end) und dann nach der zweiten Sternchenreihe die Aufgabe erstellt werden.
(Ich hab jetzt nur Codeausschnitte hier eingestellt - ich hoffe, ich kann damit mein Problem darstellen)

"return HttpResponse(zaehler.optionen)" gibt mir wunderbar die angekreuzten Optionen zurück und in "zaehler.optionen" werden sie ja auch gespeichert. Wenn ich "return HttpResponse(zaehler.optionen)" weglasse, erhalte ich die Fehlermeldung:
"The view core.views.optionen didn't return an HttpResponse object. It returned None instead."
Eigentlich muss doch gar nichts zurückgegeben werden - wie mache ich das?

Nachtrag: Ich habe es gerade nochmal nachgeprüft: Es stimmt nicht, die Auswahl wird nicht in "zaehler.optionen" abgespeichert (save() ergibt aber keine Fehlermeldung mehr)
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

So ganz kann ich das aus deinem gekürzten Code nicht ersehen. Nach "return" ist die Funktion ja zu ende, deshalb wäre der Code der Sternchen schon interessant.

Nehmen wir mal an, da steht irgendwo ein "else":

Code: Alles auswählen

if not zaehler.optionen:
    return redirect('optionen', slug)
else:
    typ_anf, typ_end = aufgaben(modul.id, jg=user.jahrgang, stufe=user.stufe, typ_anf=0, typ_end=0, optionen=zaehler.optionen)
So (optionen=zaehler.optionen) würdest du die Optionen weitergeben. Sollte es allerdings möglich sein, keine Optionen anzugeben, dann baust du hier eine Endlosschleife.

Der zweite Code speichert die gewählten Optionen?

Code: Alles auswählen

...
if form.is_valid():
    zaehler.optionen = ';'.join(map(str, form.cleaned_data['optionen']))
    zaehler.save()
    return redirect('VIEW VON OBEN')
Nach einem POST Request folgt meist ein Redirect. Du musst die save Methode also auch aufrufen (die Klammern sind wichtig) und dann zu deinem ersten View zurück.

Viele Grüße
Whitie
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Oh Mann, ich bin einfach zu blöd!
Klar, wenn ich eine Seite mit der Optionsauswahl erzeugt habe, muss ich dann auch wieder die Aufgabenseite aufrufen - mit Optionen abspeichern alleine ist es nicht getan.
Ich habe jetzt wieder ziemlich lange rumprobiert und jetzt scheint es zu klappen. Es ist aber zu blöd, was ich dazwischen alles falsch eingetippt habe! Wenn es dann mal läuft sieht dann wieder alles ganz logisch aus!

Danke wieder mal
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

So, es geht mal wieder weiter.
Das funktioniert:

Code: Alles auswählen

def optionen(req, slug):
    kategorie = get_object_or_404(Kategorie, slug=slug)
    form = AuswahlForm(kategorie=kategorie)
    user=get_fake_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 = ';'.join(map(str, form.cleaned_data['optionen']))
            if optionen=="":
                optionen="keine"
        else:
            optionen="keine"  
    else:
        auswahl=kategorie.auswahl_set.all().count()
        if auswahl>0:
            return render(req, 'core/optionen.html', {'kategorie': kategorie, 'auswahl_form':form})
        else:
            optionen="keine"
    zaehler.optionen=optionen        
    zaehler.save()
    typ_anf, typ_end = aufgaben(kategorie.id, jg=user.jahrgang, stufe=user.stufe, optionen=zaehler.optionen)
    zaehler.typ_anf=typ_anf
    zaehler.typ_end=typ_end
    zaehler.save()
    return redirect('main', slug)
... wenn ich zu der entsprechenden Kategorie Optionen (z.B. "mit Kommazahlen") angelegt habe, dann wird, bevor die erste Aufgabe erzeugt und angezeigt wird, die entsprechende Auswahlmöglichkeit angezeigt - ansonsten nicht. Jetzt ist es aber so, dass ich im model "auswahl" bei der Kategorie "addieren" "mit Kommazahlen" festlege bis zu welchem Jahrgang diese Option angezeigt werden soll. Ich muss also nicht nur überprüfen, ob es zu der Kategorie Optionen gibt, sondern auch ob der Jahrgang des users ("schueler.jahrgang") kleiner ist, als im Feld "bis_jg" festgelegt wurde. Das bekomme ich mal wieder nicht hin. Der Aufbau von "auswahl":

Code: Alles auswählen

class Auswahl(models.Model):
    kategorie = models.ForeignKey(Kategorie, on_delete=models.CASCADE)
    text = models.CharField(max_length=80, verbose_name="Text")
    bis_stufe = models.IntegerField(default=0, verbose_name="bis Stufe:")
    bis_jg = models.IntegerField(default=0, verbose_name="bis Jahrgang:")
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Wenn ich das ganze richtig verstanden habe, sollte diese Prüfung entweder in optionen.html oder direkt im auswahl_form stattfinden. Man könnte z. B. dem betreffenden Input-Feld im Formular ein disabled mitgeben, wenn die Bedingung zutrifft.

Viele Grüße
Whitie
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Jetzt weiß ich nicht so ganz, ob du mich richtig verstanden hast. mein jetziger Code überprüft, ob es überhaupt Optionen zum Auswählen innerhalb der Kategorie gibt:

Code: Alles auswählen

auswahl=kategorie.auswahl_set.all().count()
if auswahl>0:
return render(req, 'core/optionen.html', {'kategorie': kategorie, 'auswahl_form':form})
...
... das funktioniert auch - Die HTML Seite mit den Optionen zum Auswählen erscheint nur, wenn es in der entsprechenden Kategorie auch Optionen gibt. Leider weiß ich aber nicht genau, wie das funktioniert - und das ist wohl auch mein Problem. Ich habe ein model für die Kategorien und ein model für die Optionen ("Auswahl"). Im Admintool kann ich die Optionen direkt unter den Kategorien einstellen und ich habe nicht verstanden, wie ich das gemacht habe:
Bild
Es liegt wohl an diesem Code in admin.py:

Code: Alles auswählen

class AuswahlInline(admin.TabularInline):
    model = Auswahl
    extra = 0

class KategorieAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,   {'fields': ['gruppe', 'name', 'zeile', 'start_jg', 'start_sw']}),
                ('weitere Infos', {'fields': ['eof'], 'classes': ['collapse']}),        
    ]
    inlines = [AuswahlInline]
... und da ich nicht verstanden habe, was ich da gemacht habe, verstehe ich auch nicht wie "anzahl=kategorie.auswahl_set.all().count()" funktioniert.
Da ich nachts aber gerne aufwache und mir dann spontan Lösungen zu meinen Programmierfragen einfallen, habe ich halt versucht es so zu lösen wie ich es schon gelernt habe. Ich habe also mein Code so geändert:

Code: Alles auswählen

anzahl=kategorie.auswahl_set.all().count()
        if anzahl>0:
            print (user.jg)
            anzahl = Auswahl.objects.filter(bis_jg=7, kategorie=kategorie).count()
            return HttpResponse(anzahl)
... und ich bekomme auch schön eine "1" als Rückmeldung und "print(user.jg)" gibt auch schön "8" zurück. Und auch, wenn ich "bis_jg=7" durch "bis_jg=user.jg" ersetze bekomme ich "0" zurück. Was jetzt aber nicht geht ist, dass ich "bis_jg=7" durch "bis_jg>user.jg" ersetze. Das wäre das, was ich überprüfen will (denn nur die Schüler, deren Jahrgang kleiner als 8 ist, sollen diese Option angezeigt bekommen). Ich erhalte die Fehlermeldung:"name 'bis_jg' is not defined"
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Das sollte sich so lösen lassen:

Code: Alles auswählen

anzahl = Auswahl.objects.filter(bis_jg__gt=user.jg, kategorie=kategorie).count()
Siehe hier
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Whitie hat geschrieben: Sonntag 3. April 2022, 13:38 Ich hoffe du möchtest dann nicht irgendwann von diesem String wieder auf das Auswahl Model kommen? Dann wäre es Zeit über ein ManyToManyField nachzudenken.
Na klar, du hattest wie immer recht. Bisher hat das mit dem Speichern eines Strings prima ausgereicht. Jetzt bin ich dem Problem begegnet, dass ich nach 10 Aufgaben überprüfen will, ob eine Option angekreuzt wurde und, wen ja, welche Stufe damit erreicht würde (das steht ja unter "bis_stufe=..."). Wenn der user also im Jahrgang 7 "mit Kommazahlen" angekreuzt hat und 10 Aufgaben richtig hat, dann kann er das ja und wird von Stufe 3 auf Stufe 5 hochgesetzt. Ich habe, wie du empfohlen hast, das model "Zaehler" um das Feld

Code: Alles auswählen

    optionen = models.ManyToManyField(Auswahl)
ergänzt und die Abfrage mit

Code: Alles auswählen

zaehler.optionen.set(form.cleaned_data['optionen'])
gespeichert. Jetzt müsste ich nach 10 Aufgaben nachprüfen, ob die Option(en), die angekreuzt wurde(n) eine "bis_stufe" haben die größer ist als "user.stufe". Wie aber überprüfe ich, welche Option angekreuzt wurde und wie frage ich die entsprechende(n) "bis_stufe" ab. Mein Code nach 10 Aufgaben:

Code: Alles auswählen

def richtig(protokoll_id, zaehler_id, user_id):
    protokoll = Protokoll.objects.get(pk=protokoll_id)
    zaehler = Zaehler.objects.get(pk=zaehler_id)
   ...
    zaehler.richtig +=1
...
    zaehler.save()
    if zaehler.aufgnr>10:
        user = Schueler.objects.get(pk=user_id)
        print(user.stufe)
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Whitie hat geschrieben: Donnerstag 21. April 2022, 12:31 Das sollte sich so lösen lassen:

Code: Alles auswählen

anzahl = Auswahl.objects.filter(bis_jg__gt=user.jg, kategorie=kategorie).count()
Siehe hier
Oh Mann! Das ist ja schon wieder peinlich. Das mit dem Unterstrich hatte ich ja sogar probiert (immerhin ist das jetzt das dritte Mal, dass du mich darauf hinweisen musst) und das mit dem "gt" hatte ich ja auch schon gelesen ... jetzt müsste ich nur noch alles gleichzeitig berücksichtigen!
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Ich Habe mal wieder Zeit (ich bin zurzeit in Griechenland und das Wetter ist schlecht) und komme hier nochmal auf meinen Post vom 21.4.22 zurück. Es ist mir noch nicht gelungen dieses Problem zu lösen:
Pitwheazle hat geschrieben: Donnerstag 21. April 2022, 12:48
Whitie hat geschrieben: Sonntag 3. April 2022, 13:38 Ich hoffe du möchtest dann nicht irgendwann von diesem String wieder auf das Auswahl Model kommen? Dann wäre es Zeit über ein ManyToManyField nachzudenken.
Na klar, du hattest wie immer recht. Bisher hat das mit dem Speichern eines Strings prima ausgereicht. Jetzt bin ich dem Problem begegnet, dass ich nach 10 Aufgaben überprüfen will, ob eine Option angekreuzt wurde und, wen ja, welche Stufe damit erreicht würde (das steht ja unter "bis_stufe=..."). Wenn der user also im Jahrgang 7 "mit Kommazahlen" angekreuzt hat und 10 Aufgaben richtig hat, dann kann er das ja und wird von Stufe 3 auf Stufe 5 hochgesetzt. Ich habe, wie du empfohlen hast, das model "Zaehler" um das Feld

Code: Alles auswählen

    optionen = models.ManyToManyField(Auswahl)
ergänzt und die Abfrage mit

Code: Alles auswählen

zaehler.optionen.set(form.cleaned_data['optionen'])
gespeichert. Jetzt müsste ich nach 10 Aufgaben nachprüfen, ob die Option(en), die angekreuzt wurde(n) eine "bis_stufe" haben die größer ist als "user.stufe". Wie aber überprüfe ich, welche Option angekreuzt wurde und wie frage ich die entsprechende(n) "bis_stufe" ab. Mein Code nach 10 Aufgaben:

Code: Alles auswählen

def richtig(protokoll_id, zaehler_id, user_id):
    protokoll = Protokoll.objects.get(pk=protokoll_id)
    zaehler = Zaehler.objects.get(pk=zaehler_id)
   ...
    zaehler.richtig +=1
...
    zaehler.save()
    if zaehler.aufgnr>10:
        user = Schueler.objects.get(pk=user_id)
        print(user.stufe)
... dann kommt da noch dazu, dass ich meine Einstellnegn (Aufgabennummer, Aufgabentyp (von bis)... in "zaehler" speichere. Nach 10 Aufgaben bzw. nach Klick auf "abbrechen" setze ich einige Einstellungen (z.B. die Aufgabennummer, aber auch die Wahl in "Optionen" (hier "mit Kommazahlen") zurück. Solange ich einen String speichere,bekomme ich das mit

Code: Alles auswählen

zaehler.optionen_text=""

hin - wie setzte ich aber die Auswahl zurück, wenn ich sie im Feld

Code: Alles auswählen

class Zaehler(models.Model):
...    
    optionen = models.ManyToManyField(Auswahl)
...
gespeichert habe ... Wenn sie dort überhaupt gespeichert habe ... das habe ich, wie man erkennen kann, eben noch nicht verstanden.
Viele Grüße aus Andros
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Das kannst du hier nachlesen.

Bei deinem Beispiel sollte es etwa so aussehen:

Code: Alles auswählen

zaehler.optionen_set.remove(<AUSWAHL ZUM ENTFERNEN>)
Viele Grüße
Whitie
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Na dann weiß ich schon mal nach was ich suchen muss und wo. Das sieht aber nach schwierig aus - mal sehen, ob ich das schaffe - eine Zeitlang war ich hoffnungsvoll, jetzt fühle ich mich wieder alt und etwas überfordert. Aber frisch ans Werk!
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Lieber Whitie, ich bekomme das nicht alleine hin - wahrscheinlich, weil ich das ganze Prinzip noch nicht verstanden habe.
Ich versuche hier nochmal die Bausteine einzustellen und zu beschreiben was ich verstanden habe und was nicht:

Wenn der user eine Kategorie anklickt,, ist das Feld "zaehle.optionen" leer. Es wird überprüft, ob für die Kategorie, für die Stufe und den Jahrgang Optionen da sind. Falls nicht wird in "zaehler.optionen" "keine" eingetragen, ansonsten wird eine HTML Abfrage angezeigt, z.B. "mit Kommazahlen" (es werden später in anderen Kategorien aber auch noch andere Optionen dazukommen).
Wenn Optionen vorhanden sind, wird die Funktion für die entsprechenden Kategorie (z.B. "addieren") aufgerufen und festgelegt von welchem Typ Aufgaben erstellt werden ("typ_anf" bis "typ_end") und diese in den entsprechenden Feldern von "zaehler" eingetragen. Bei der zweiten und jeder weiteren Aufgabe werden dann die Aufgaben aus diesem Bereich erstellt.
Nach der zehnten Aufgabe, oder wenn "abbrechen" angeklickt wird, wird in "zaehler" das Felder "optionen", gelöscht (und der Aufgebenzähler auf Null gesetzt). Beim nächsten Start einer Kategorie erfolgt dann wieder u.U. die Abfrage der Optionen. Soweit funktioniert das.

Code: Alles auswählen

def main(req, slug):
    modul = get_object_or_404(Kategorie, slug = slug)
    user = get_fake_user()    
    zaehler = get_object_or_404(Zaehler, kategorie = modul, user = user)
    if req.method == 'POST':
...
    else:
...
        if zaehler.optionen == "":
            return redirect('optionen', slug)
...

def optionen(req, slug):
    kategorie = get_object_or_404(Kategorie, slug = slug)
    form = AuswahlForm(kategorie = kategorie)
    user = get_fake_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():
            zaehler.optionen.set(form.cleaned_data['optionen'])
            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__gt = user.stufe,kategorie = kategorie).count()
            return render(req, 'core/optionen.html', {'kategorie': kategorie, 'auswahl_form':form})
        else:
            optionen_text = "keine"
    zaehler.optionen_text = optionen_text        
    zaehler.save()
    typ_anf, typ_end = aufgaben(kategorie.id, 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)
Gelöst habe ich das mit deinem Code:

Code: Alles auswählen

optionen_text = ';'.join(map(str, form.cleaned_data['optionen']))
... der einfach den Text "mit Kommazahlen" speichert, oder auch nicht, jenachdem, ob es angeklickt wurde.

Vorher hattest du mir den Code

Code: Alles auswählen

zaehler.optionen.set(form.cleaned_data['optionen'])
empfohlen, von dem ich nicht weiß, was er macht. Wenn ich unter admin nachschaue, steht zweimal "mit Kommazahlen" in "zaehler":
Bild
... ich hatte geadcht, der Code verknüpft die gewählten Optionen im Feld "zaehler.optionen" - da tauchen aber zwei Einträge auf - warum? Und die stehen da drin, egal, ob angewählt oder nicht. (Das Problem hatte ich schon mal beschrieben).
Und diese Verknüpfung (ist es den eine?) müsste ich doch jetzt nach 10 Aufgaben löschen mit:

Code: Alles auswählen

zaehler.optionen_set.remove(<AUSWAHL ZUM ENTFERNEN>)
?
Aber was trage ich da unter <AUSWAHL ZUM ENTFERNEN> ein? Meines Erachtens müssten doch alle Verknüfungen gelöscht werden.
Du siehst, ich habe es immer noch nicht kapiert und ich habe mich mit dem Link zum Mannual beschäftigt, das kapiere ich aber nicht :(

Und das nächste Problem: Nach 10 Aufgaben will ich, wenn die Option gewählt wurde, nachprüfen, welcher Eintrag unter "bis_stufe" und "bis_jg" steht:

Code: Alles auswählen

class Auswahl(models.Model):
    kategorie = models.ForeignKey(Kategorie, null=True, on_delete=models.CASCADE)
    text = models.CharField(max_length=80, verbose_name="Text")
    bis_stufe = models.IntegerField(default=0, verbose_name="bis Stufe (ex):")
    bis_jg = models.IntegerField(default=0, verbose_name="bis Jahrgang:")
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Also für das obige Problem habe ich eine andere Idee - die ist sicher etwas umständlich.

Zwischenzeitlich habe ich mich aber mit dem Problem der Registrierung beschäftigt und, erwartungsgemäß wieder einige Probleme/Fragen.
Ich muss ja wohl mein model "schueler" aus der App "core" (wo meine Aufgaben verwaltet werden rausnehmen und mich mit der offiziellen Django - Authentifizierung beschäftigen. Folgendes habe ich in der neuen App "register" unter "forms.py":

Code: Alles auswählen

from django import forms
from django.db import models

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.core.validators import MinValueValidator, MaxValueValidator

class wahl_kurs(models.TextChoices):
    GYMNASIUM = 'Y', 'Gymnasium'
    REALSCHULE = 'R', 'Realschule'
    HAUPTSCHULE = 'H', 'Hauptschule'
    E_KURS = 'E', 'E-Kurs'
    G_KURS = 'G', 'G-Kurs'
    A_KURS = 'A', 'A-Kurs'
    B_KURS = 'B', 'B-Kurs'
    C_KURS = 'C', 'C-Kurs'
    FOERDER = 'i', 'Förderschüler'

class RegisterForm(UserCreationForm):
    email = forms.EmailField()
    nachname = forms.CharField(max_length=20)
    vorname = forms.CharField(max_length=20)
   
    klasse = forms.CharField(max_length=10)
    jg = forms.IntegerField(validators=[MinValueValidator(5), MaxValueValidator(10)])
    #kurs= forms.CharField(max_length=1, choices=wahl_kurs.choices, default=wahl_kurs.E_KURS,)
    stufe=forms.IntegerField()    

    def save(self, *args, **kwargs):
        if jg <5:
            self.stufe=1
        else:
            self.stufe=3    
        super().save(*args, **kwargs)
        
    def __str__(self):
        return f"({self.vorname} {self.nachname}, {self.klasse})"
Nutzername, Email und Passwort funktioniert soweit. Ich möchte aber, dass der/die Nutzer/in auch eine Klassen, den Jahrgang und einen Kurs angibt. Da habe ich einfach mal das übernommen, was mit den models noch funktioniert hat - hier geht das nicht so einfach:

1. Der min/max Validator bei Jg (Jahrgang)scheint nicht beachtet zu weden
2. Auch beim Kurs, scheint das mit einer Auswahl bei forms nicht vorgesehen zu sein
3. Dann möchte ich, je nach Jahrgang und Kurs, eine Stufe vergeben. bei "def save..." erfogt keine Fehlermeldung, ich kann aber nicht überprüfen, ob das klappt, denn
4. Mein/e user/in wird doch wohl in der Datenbank gespeichert. Im Adminzugang finde ich aber nix derartiges. Wie kann ich die Daten auslesen?
5. Und zuletzt: Die "stufe" wird auf der Eingabeseite auch angezeigt, die Stufe will ich aber selbst vergeben (s.o.)

Ich habe jetzt einige Tutorien dazu bearbeitet, die unterscheiden sich aber alle. Und ich habe auch versucht mich in die Django Dokumentation reinzuarbeiten, schaffe aber auch das nicht ohne Hilfe.
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Zum Zähler:
Wenn du alle Optionen zurücksetzen möchtest, brauchst du nicht überlegen, was du remove übergibst (es wäre entweder das Objekt oder die ID). Du kannst einfach

Code: Alles auswählen

zaehler.optionen_set.clear()
aufrufen.

Zu deinem Bild von der Admin-Oberfläche:
Du siehst in dem Feld (Many-To-Many) immer alle Möglichkeiten, die es gibt. D. h. auch welche, die es für diese Kategorie nicht gibt. Django weiß nicht, das bestimmte Kategorien nicht alle Optionen haben. Das sollte aber erstmal nicht so tragisch sein, man sieht es ja nur im Admin. Du kannst das später über die admin.py noch beeinflussen.

Zur Registrierung:
Du kannst das User-Model von Django erweitern mit deinen Daten oder auch komplett austauschen. Dazu gibt es extra einen Abschnitt in der Dokumentation.

Viele Grüße
Whitie
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Mit

Code: Alles auswählen

zaehler.optionen..clear()

kommt jetzt zumindest kein Fehler mehr. Jetzt gelingt es mir aber nicht (nach 10 Aufgaben) darauf zuzugreifen. Wenn Ich z.B. am Anfang "mit Kommazahlen" und "noch eine Option" auswähle, müsste ich jetzt den jeweiligen Eintrag "bis_stufe" auswerten. Wenn ich das richtig verstanden habe, dann wird, bzw. werden, wenn ich am Anfang diese beiden Optionen angeklickt habe, diese, an dieser Stelle:

Code: Alles auswählen

        if form.is_valid():
            zaehler.optionen.set(form.cleaned_data['optionen'])
            optionen_text = ';'.join(map(str, form.cleaned_data['optionen']))
als Verknüfung in "Zaehler.optionen" gespeichert (und später werden diese Verknüpfungen mit "zaehler.optionen.clear()" wieder entfernt?

Ich hatte zwischenzeitlich folgendens probiert
Also für das obige Problem habe ich eine andere Idee - die ist sicher etwas umständlich.

Code: Alles auswählen

   if zaehler.optionen_text != "":     #wenn Otionen gewählt wurden wird hier die Stufe entsprechend höhergesetzt
                        auswahl = Auswahl.objects.filter(kategorie__name = slug)
                        optionen = zaehler.optionen_text.split(";")
                        for o in optionen:
                            wahl = auswahl.filter(text = o)
                            print(wahl.bis_stufe)
und erhalte den Fehler:

Code: Alles auswählen

'QuerySet' object has no attribute 'bis_stufe' if zaehler.aufgnr>10
Mein model "Auswahl":

Code: Alles auswählen

class Auswahl(models.Model):
    kategorie = models.ForeignKey(Kategorie, null=True, on_delete=models.CASCADE)
    text = models.CharField(max_length=80, verbose_name="Text")
    bis_stufe = models.IntegerField(default=0, verbose_name="bis Stufe (ex):")
    bis_jg = models.IntegerField(default=0, verbose_name="bis Jahrgang:")
und das Model "Zaehler":

Code: Alles auswählen

class Zaehler(models.Model):
    user = models.ForeignKey(Schueler, verbose_name='Benutzer', related_name='zaehler', on_delete=models.CASCADE)    
    kategorie = models.ForeignKey(Kategorie, on_delete=models.CASCADE, related_name="zaehler")
    
    optionen = models.ManyToManyField(Auswahl)
    optionen_text=models.CharField(max_length=100, blank=True, verbose_name="Optionen")
    ...
Zur Registrierung:
Du kannst das User-Model von Django erweitern mit deinen Daten oder auch komplett austauschen. Dazu gibt es extra einen Abschnitt in der Dokumentation.
... das ist mir ja ansatzweise auch gelungen, es scheint aber keine Möglichkeit zu geben, ein Min/max Validation einzufügen und mit

Code: Alles auswählen

kurs= forms.CharField(max_length=1, choices=wahl_kurs.choices, default=wahl_kurs.E_KURS,)
die Möglichkeit zu geben, den Kurs aus einer Liste auszuwählen.
Zwischenzeitlich denke ich, es wäre wohl sinnvoller, die Authetifizierung und das model mit dem Schüler mit eine onetoone Relation zu verknüpfen (wenn ich auch noch nicht weiß, wie das geht).
Antworten