Mein Problem ist schwer zu beschreiben

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

Mein Rechenduell funktioniert - nur ein Ding bei der Anzeige bekomme ich nicht hin und habe möglicherweise einen Denkfehler. Ich zeige hier zunächst mal einen Screenshot:
Bild
Eine Aufgabe wird erstellt und alle Daten dazu in der Tabelle "Protokoll" gespeichert. In der Tabelle "Duellanten" werden die Duellanten gespeichert und in der Tabelle "Duell_Protokoll" werden die beiden ausgelosten Duellanten mit ihren Punktzahlen gespeichert.
Hier zunächst die (entspeckten) Tabellen:

Code: Alles auswählen

class Duellant(models.Model):
    profil = models.OneToOneField(Profil, related_name='duellprofil', on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    punkte = models.DecimalField(max_digits=3, decimal_places=1, default=0)
    punkte_spiel = models.DecimalField(max_digits=2, decimal_places=1, default=0)

class Duell_Protokoll(models.Model):
    protokoll = models.ForeignKey(Protokoll, related_name='duellprotokoll', on_delete=models.CASCADE)
    gruppe = models.ForeignKey(Lerngruppe, related_name='duellgruppe', on_delete=models.CASCADE)
    duellant_1 = models.ForeignKey(Duellant, related_name='duellant_1', null = True, on_delete=models.SET_NULL)
    duellant_2 = models.ForeignKey(Duellant, related_name='duellant_2', null = True, on_delete=models.SET_NULL)
und hier der (entspeckte) Code der Views:

Code: Alles auswählen

def sub_punkte(req, duell_protokoll, duellant, duellant_nr, eingabe, punkte, beide = False, duell_eingabe = None):
    duellant.punkte_spiel += punkte
    print(duellant, " - Punkt : ",punkte)
    duellant.save()
    print("Protokoll: :", duell_protokoll, " - ", duell_protokoll.duellant_1, " - ", duell_protokoll.duellant_1, duell_protokoll.duellant_1.punkte_spiel)
    print("Protokoll: :", duell_protokoll, " - ", duell_protokoll.duellant_2, " - ", duell_protokoll.duellant_2, duell_protokoll.duellant_2.punkte_spiel)
    return

def sub_eingabe_speichern(req, duell_protokoll, duellant, eingabe, punkte, beide):
    if duellant.name == duell_protokoll.duellant_1.name:
        duellant_nr = 1
    else:
        duellant_nr = 3
    sub_punkte(req, duell_protokoll, duellant, duellant_nr, eingabe, punkte, False )    # übergibt die "duellant_nr", die wird benötigt damit im Protokoll die Eingabe und Punkte links(1) oder rechts(3) zugeordnet werden
    return

def duell_kontrolle(req):
    meldung = ""
    gruppe = Lerngruppe.objects.get(pk = req.session.get('gruppe_id'))
    protokoll = Protokoll.objects.get(pk = req.session.get('protokoll_id'))
    duell_protokoll = Duell_Protokoll.objects.get(pk = req.session.get('duell_id'))
    context = dict()
    form = AufgabeFormZahl(req.POST)
    if form.is_valid():
        eingabe = pro_eingabe = form.cleaned_data['eingabe']
        req.session['eingabe'] = duell_protokoll.id
        wertung, rueckmeldung = kontrolle(eingabe, protokoll.wert, protokoll.loesung, protokoll.id)
        duellant_name = req.POST.get('duellant')
        beide = False
        duellant = Duellant.objects.get(name=duellant_name)
        #wenn Eingabe richtig:
        if wertung > 0  :
            rueckmeldung = "Die letzte Aufgabe war richtig!"+ rueckmeldung
            punkte = 1
            sub_eingabe_speichern(req, duell_protokoll, duellant, eingabe, punkte, beide)
            messages.info(req, f'{rueckmeldung}')
            context['richtig'] = True
        else:
            punkte = Decimal(-0.5)
            messages.info(req, f'Die letzte Aufgabe war leider falsch! Versuche: {protokoll.versuche}')#, {msg}') 
            sub_eingabe_speichern(req, duell_protokoll, duellant, eingabe, punkte, beide)
        context['falsch'] = True
    context.update(protokoll = protokoll, duell_protokoll = duell_protokoll, parameter = protokoll.parameter,   
        eingabe = eingabe, form = form)
    return render(req, 'duell_aufgabe.html', context)
Das Problem ist, dass, wenn der/die zweite Duellant gewinnt, wird die Punktzahl im Template angezeigt, wenn aber der/die erste gewinnt nicht. Der Punkt wird auf der Übersichtseite gewertet und nach Refresch der HTML Seite auch angezeigt, aber halt nur nach einem Refresch und nicht gleich. Aber nur beim oberen - unten klappt es sofort.
Das kann man auch bei den beiden "print" Befehlen erkennen. Der Punkt wird angezeigt (und an das Template übergeben) wenn unten gewinnt, wenn oben gewinnt nicht:

Code: Alles auswählen

Protokoll: : lehrer, Testgruppe: Fritz_2 vs Lisa  -  Fritz_2  -  Fritz_2 0.0
Protokoll: : lehrer, Testgruppe: Fritz_2 vs Lisa  -  Lisa  -  Lisa 0.0
[27/Aug/2024 13:38:21] "POST /duell_kontrolle/ HTTP/1.1" 200 7085
[27/Aug/2024 13:40:45] "GET /duell_aufgabe/addieren/ HTTP/1.1" 200 7347
Not Found: /favicon.ico
[27/Aug/2024 13:40:45,519] - Broken pipe from ('127.0.0.1', 64525)
Fritz  - Punkt :  1
Protokoll: : lehrer, Testgruppe: Franz vs Fritz  -  Franz  -  Franz 0.0
Protokoll: : lehrer, Testgruppe: Franz vs Fritz  -  Fritz  -  Fritz 1.0
[27/Aug/2024 13:40:53] "POST /duell_kontrolle/ HTTP/1.1" 200 7081
Ich bin ziemlich verzweifelt - ich bekomme es nicht raus - wo ist mein Denkfehler? Liegt es daran, dass ich hier zweimal auf den Duellanten zugreife:

Code: Alles auswählen

class Duell_Protokoll(models.Model):
    protokoll = models.ForeignKey(Protokoll, related_name='duellprotokoll', on_delete=models.CASCADE)
    gruppe = models.ForeignKey(Lerngruppe, related_name='duellgruppe', on_delete=models.CASCADE)
    duellant_1 = models.ForeignKey(Duellant, related_name='duellant_1', null = True, on_delete=models.SET_NULL)
    duellant_2 = models.ForeignKey(Duellant, related_name='duellant_2', null = True, on_delete=models.SET_NULL)
... reichen die Codeschnipsel?
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum hat Duelant einen Namen und auch einen Verweis auf das Profil, wo doch auch der Name drinsteht? Warum gibt es Punkte Und Punkte_Spiel?
Und was ist der Unterschied zwischen einem Protokoll und einem Duell_Protokoll?
Warum hat ein Duell_Protokoll eine Lerngruppe, wo doch wahrscheinlich im Profil jedes Duelanten auch die Lerngruppe gespeichert ist?
Klassen schreibt man als CamelCase ohne Unterstriche. Die Groß-Klein-Schreibung trennt ja schon einzelne Wörter.

Die Funktion sub_punkte braucht eigentlich nur `duellant` und `punkte` als Argument, alle andren 7 Argumente sind unnötig. Warum heißt eine Funktion sub_punkte, wenn da punkte addiert werden?
`sub_eingabe_speichern` macht daher als Funktion gar keinen Sinn. Die magischen Werte 1 oder 3 sind magisch.
Was ist denn an pro_eingabe besser als an eingabe?
Warum die Protokoll-Id in session['eingabe'] gespeichert wird, wo sie doch zwei Zeilen davor aus duell_id gelesen wird?
gruppe und protokoll läßt sich alles aus duell_protokoll ableiten, braucht mal also nicht extra abfragen.
Wie bei context.update benutzt man update nicht.
Wenn es einen Duellant 1 und 2 gibt, dann ist die einzige Rückgabe als Post doch die Nummer, nicht der Name.
context sollte immer die gleichen Schlüssel haben, nicht mal ein "richtig" und mal nicht.
Warum ist "falsch" immer True?
Ich würde ja erwarten, dass es einen "status" gibt, der entweder den Wert "richtig" oder "falsch" hat.
Der Aufruf von sub_eingabe_speichern ist in beiden if-Zweigen identisch, kann also enfach danach stehen.
Ein -0.5 in Decimal zu packen ist unsinnig.

Insgesamt macht der ganze Code wenig Sinn.

Die eigentlich interessanten Codestellen, also das Erzeugen der des Duells und die passenden Templates fehlen.
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Auweh, da muss ich das mal aufdröseln - aber Danke schon mal, dass du dich dieses Problems annimmst:
Ich habe ja geschrienben, dass ich den Code "entspeckt" habe. Vor allem gibt es die Möglichkeit, dass beide Duellanten gleichzeitig die richtige Lösung finden, das habe ich im geposteteten Code weggelassen und dann gibt es ja auch noch Wetetabellen, die in den Aufgaben vorkommen, auch die habe ich weggelassen. Der "entspeckte" Code funktioniert (wenn man nicht auf "gleich schnell" klickt. Ich wollte das nicht so unübersichtlich machen.
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Warum hat Duelant einen Namen und auch einen Verweis auf das Profil, wo doch auch der Name drinsteht? Warum gibt es Punkte Und Punkte_Spiel?
"punkte" zählt die Punkte über das ganze Duell - das kann ja über ein Schulhalbjahr gehen.
"punkte_spiel" zählt nur die Punkte wenn zwei Duellanten bei einer Aufgabe gegeneinander antreten - meistens nur 1 oder -0,5, manchmal aber auch noch Extrapunkte die die Lehrkraft vergibt. Angezeigt wird bei der Aufgabe die "punkte_spiel" und in der Übersicht die "punkte".
Damit nicht "Marie Luise von Schell-Silverstein" in der Übersicht angezeigt wird, wird am Anfang nur der Vorname in die Duellantenliste eingetragen und um Doppelnennungen zu vermeiden, muss die Lehrkraft die mit z.B. "Ali_E." ersetzen.
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Und was ist der Unterschied zwischen einem Protokoll und einem Duell_Protokoll?
Das habe ich in der Frage beschrieben. In der Tabelle "Protokoll" steht alles zur gestellten Aufgabe. Aufgabentext, Lösung, Hilfetexte und natürlich auch die ganzen Daten für eventuelle Grafiken. Die werden immer gebraucht, also auch, wenn das Duell nicht aufgerufen wird. In "Duell Protokoll" steht, wer gegen wen in dieser Aufgabe antritt und welche Punkte er erreicht hat.

Code: Alles auswählen

Die Funktion sub_punkte braucht eigentlich nur `duellant` und `punkte` als Argument, alle andren 7 Argumente sind unnötig. Warum heißt eine Funktion sub_punkte, wenn da punkte addiert werden?
Ich habe ja geschrieben, dass ich die Möglichkeit, dass zwei Duellanten die Punkte bekommen weggelassen habe, die macht den Code umfangreicher. Wen sich das jemand antuen möchte, dann kopiere ich unten den ganzen Code. Hier wird auch noch in "Duell_Eingabe" protokolliert, wer was eingegeben (angegeben) hat und ob, bei den Punkten noch Änderungen seitens der Lehrkraft vorgenommen wurden.
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 `sub_eingabe_speichern` macht daher als Funktion gar keinen Sinn. Die magischen Werte 1 oder 3 sind magisch.
Auch hier habe ich wieder Code weggelassen. Es gibt ein Protokoll, indem man jede Aufgabe nachvollziehen kann. Der Wert 1 sorgt dafür, dass im Protokoll, die Eingabe und die Bepunktung links beim Duellanten_ 1 steht, bei 2, bekommen beide den Punkt und bei drei , der rechte:
Bild
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Was ist denn an pro_eingabe besser als an eingabe?
Es gibt bei einigen Aufgaben, z.B. bei Sachaufgaben und bei der Wahrscheinlichkeitsrechnung sehr lange Texte. Da wird extra für das Protokoll, der Text verkürzt.
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Wenn es einen Duellant 1 und 2 gibt, dann ist die einzige Rückgabe als Post doch die Nummer, nicht der Name.
Der Name wird aus dem template zurückgegeben.
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 context sollte immer die gleichen Schlüssel haben, nicht mal ein "richtig" und mal nicht.
Warum ist "falsch" immer True?
Das ergibt sich aus den Möglichkeiten, die ich benötige um mit JavaScript die Anzeige und Sichtbarkeit der einzelnen Felder im Template zu steuern. (Ich fürchte, ich muss meinen ganzen Code hier einstellen.)
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Ich würde ja erwarten, dass es einen "status" gibt, der entweder den Wert "richtig" oder "falsch" hat.
Hier steckt wohl möglicherweise ein Ansatz mit dem ich das ursprüngliche Problem angehen könnte. Ich habe nämlich festgestellt, dass die einem Refresch der Seite nicht etwa der erreichte Punkt angezeigt wird, sondern ein weiterer Punkt addiert wird. Es gibt aber außer richtig und falsch auch noch die Möglichkeit, dass die Lehrkraft die Bepunktuntung editiert und da ist der "Status" "edit".
Also soll ich wirklich meinen ganzen Code hier posten? Das ist jetzt aber nur das Duell und nicht die Aufgabenstellung und das zugehörige "Protokoll".
Also meine views (zumindest die wichtigsten):

Code: Alles auswählen

import random
from py_expression_eval import Parser

from decimal import *

from django.contrib import messages
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.http import HttpResponse 

from django.db.models import Count 

from accounts.models import Profil, Lerngruppe
from accounts.views import stufe_aus_jg

from core.models import Kategorie, Auswahl, Protokoll, Zaehler 
from core.forms import AufgabeFormZahl, AufgabeFormStr
from core.views import format_zahl, aufgaben, kontrolle

from .models import  Duellant, Duell_Protokoll, Duell_Eingabe
from .forms import Duellant_Aendern_Form, Duell_AuswahlForm, AufgabeFormTab, DuellProtokollFilter

# das Rechenduell
def duell_uebersicht(req, gruppe_id):
    gruppe = get_object_or_404(Lerngruppe, pk=gruppe_id)
    if gruppe.lehrer != req.user and not req.user.is_superuser:
        return HttpResponse("Zugriff verweigert")
    profil = get_object_or_404(Profil, user=req.user)
    profil.duell_gruppe = gruppe_id
    profil.save() 
    duellanten = Duellant.objects.filter(profil__gruppe=gruppe_id)
    if duellanten.count() == 0:                         # löscht die gespeicherten Aufgabennummern der einzelnen Kategorien der Lehrkraft
        zaehler = Zaehler.objects.filter(user = req.user.profil)
        for kategorie in zaehler:
            kategorie.aufgnr = 0
            kategorie.save()
    duell_rang(gruppe.id)
    schueler_liste = Profil.objects.filter(gruppe=gruppe).order_by("user__profil__vorname")
    for schueler in schueler_liste:
        duellant, created = Duellant.objects.get_or_create(profil = schueler)
        if created:
            duellant.name = schueler.vorname
            duellant.save()
    dubletten = duellanten.values('name').annotate(dubletten=Count('name')).filter(dubletten__gt=1)
    dubletten_liste = []
    if not dubletten:
        pass
    else:
        for dublette in dubletten:
            dubletten_liste.append(dublette["name"])
    leerstellen_liste = []
    for duellant in duellanten:
        if " " in duellant.name:
            leerstellen_liste.append(duellant.name)
    duellanten = duellanten.filter(profil__gruppe = gruppe).order_by("liga", "platz", "profil__vorname", )
    duell_rang(gruppe.id)
    if req.method == 'POST': 
        IDs = list(req.POST.getlist('ID'))
        for duellant in duellanten:
            duellant.abwesend = True if str(duellant.id) in IDs else False
            duellant.save()
    req.session['gruppe_id'] = gruppe_id  
    context={'gruppe_id': gruppe_id, 'gruppe': gruppe, 'duellanten': duellanten, 'dubletten_liste': ", ".join(dubletten_liste), 'leerstellen_liste': ", ".join(leerstellen_liste),'titel': "Schülerdaten ändern"} 
    return render(req, 'duell_uebersicht.html', context)

def duell_start(req, gruppe_id):
    gruppe = Lerngruppe.objects.get(pk = req.session.get('gruppe_id'))
    if gruppe.lehrer != req.user and not req.user.is_superuser:
        return HttpResponse("Zugriff verweigert") 
    kategorien = Kategorie.objects.all().order_by('zeile')
    zaehler = Zaehler.objects.filter(user = req.user.profil)
    for item in zaehler:
        item.optionen_text = ""
        item.save()
    context={'gruppe': gruppe, 'kategorien': kategorien} 
    return render(req, 'duell_start.html', context)

def duellant_aendern(req, gruppe_id, duellant_id):
    gruppe = get_object_or_404(Lerngruppe, pk=gruppe_id)
    if gruppe.lehrer != req.user:
        return HttpResponse("Zugriff verweigert")
    duellanten = Duellant.objects.filter(profil__gruppe = gruppe_id).order_by("liga", "platz", "profil")
    duellant = Duellant.objects.get(pk = duellant_id)
    if duellant.profil.gruppe.lehrer != req.user and not req.user.is_superuser:
        return HttpResponse("Zugriff verweigert") 
    if req.method == 'POST':
        form = Duellant_Aendern_Form(req.POST, instance=duellant)
        if  form.is_valid():
            form.save() 
            if duellant.spiele != 0:
                duellant.pps = duellant.punkte/duellant.spiele
                duellant.save()             
        return duell_uebersicht(req, gruppe_id)
    form = Duellant_Aendern_Form(instance=duellant)
    return render(req, 'duellant_aendern.html', {'gruppe_id': gruppe_id, 'duellanten': duellanten, 'duellant': duellant, 'form': form, 'edit':True})

def duell_aufgabe(req, slug):
    gruppe = Lerngruppe.objects.get(pk = req.session.get('gruppe_id'))
    if gruppe.lehrer != req.user:
        return HttpResponse("Zugriff verweigert")
    #duell_rang(gruppe.id)
    kategorie = get_object_or_404(Kategorie, slug = slug)
    user = req.user.profil
    zaehler, created = Zaehler.objects.get_or_create(user = user, kategorie = kategorie)
    if zaehler.aufgnr == 0:     # Das ist jeweils die erste Aufgabe von 10
        zaehler.aufgnr = 1
    #hier wird die entsprechende Funktion aufgerufen und festgelegt, aus welchem Bereich (Typ) Aufgaben erzeugt werden
    #zunächst wird überprüft, ob für diese kategorie Einträge bei "Optionen" vorhanden sind:
    if not zaehler.optionen_text :  
        return redirect('duell_optionen', slug)
    #!!!!!!!! hier wird dann die nächste Aufgabe erzeugt: 
    if kategorie.slug == "sachaufgaben":
        try:  
            user.voreinst["sachaufg"] = user.voreinst["sachaufg"] + 1
        except:                                       
            user.voreinst.update({"sachaufg" : random.randint(1,20)})
        user.save()
        typ_anf = user.voreinst["sachaufg"]
    else:
        typ_anf = zaehler.typ_anf  
    typ_end = zaehler.typ_end  
    jg = gruppe.jg          
    stufe=(stufe_aus_jg(gruppe.jg))
    #unter Umständen gibt es auch spezielle Aufgaben für A-Kurs und Gymnasium - dazu wird hier die Stufe um 0,2 hochgesetzt
    if kategorie.name in ("Prozentrechnung","Bruchteile"):
        if user.kurs == "A" or user.kurs == "Y":
            stufe = stufe + 0.2
    typ, typ2, titel, text, pro_text, frage, variable, einheit, anmerkung, lsg, hilfe_id, ergebnis, parameter = aufgaben(kategorie.zeile, jg = jg, stufe = stufe, aufgnr = zaehler.aufgnr, typ_anf = typ_anf, typ_end = typ_end, optionen = "") 
    if kategorie.slug == "sachaufgaben":
        user.voreinst["sachaufg"] = typ
        user.save()
    if not titel:
        titel = kategorie.name
    text = text.format(*variable)
    if pro_text != "" :
        pro_text = pro_text.format(*variable)
    frage = frage.format(*variable)
    duellant_1, duellant_2 = sub_auslosen(gruppe.id)
    protokoll = Protokoll.objects.create(
        user = user, titel = titel, sj = user.sj, hj = user.hj, kategorie = kategorie, text = text, pro_text = pro_text, variable = variable, frage = frage, einheit = einheit, 
        anmerkung = anmerkung, wert = ergebnis, loesung = lsg, hilfe_id = hilfe_id, parameter = parameter, wertung = "Duell", typ = typ, typ2 = typ2, aufgnr = zaehler.aufgnr,        
    )                                                                   #Protokoll wird erstellt
    duell_protokoll = Duell_Protokoll.objects.create(
        protokoll = protokoll, gruppe = gruppe, duellant_1 = duellant_1, duellant_2 = duellant_2 
    ) 
    #Jenachdem, ob ein Wert oder ein Text erwartet wird:
    if "tab" in protokoll.parameter["name"]:
        # if "term" in protokoll.parameter["name"]:
        #     form = DuellFormTerm(req.POST)
        # else:
        form = AufgabeFormTab(req.POST)
    else:
        if protokoll.wert:
            form = AufgabeFormZahl(req.POST)
        #wenn in den Aufgaben erg=None:
        else:
            form = AufgabeFormStr(req.POST)

    if duellant_1.liga != duellant_2.liga:
        meldung = "Aufstiegsduell:"
    elif duellant_1.aufsteiger != duellant_2.aufsteiger:
        meldung = 'Relegationsspiel'
    else:
        meldung = ""
    req.session['protokoll_id'] = protokoll.id  
    req.session['duell_id'] = duell_protokoll.id 
    aufsteiger_1 = "↑" if duell_protokoll.duellant_1.aufsteiger else ""
    aufsteiger_2 = "↑" if duell_protokoll.duellant_2.aufsteiger else "" 
    context = dict(protokoll = protokoll,  duell_protokoll = duell_protokoll, parameter = parameter,   
        farbe_1 = "null", farbe_2 = "null", aufsteiger_1 = aufsteiger_1, aufsteiger_2 = aufsteiger_2, 
        form = form, message_unten = anmerkung, meldung = meldung, neu = "neu")
    return render(req, 'duell_aufgabe.html', context)

def sub_auslosen(gruppe_id):
    duellanten = Duellant.objects.filter(profil__gruppe=gruppe_id)
    duellanten = duellanten.exclude(abwesend=True).order_by("-spiele")
    duellanten_liste = []
    for duellant in duellanten:
        duellanten_liste.append(duellant.id)
    duellant_1 = duellanten.last()
    duellant_1.spiele +=1
    duellant_1.punkte_spiel = 0
    duellant_1.save()
    duellanten = duellanten.exclude(name=duellant_1.name)
    duellanten = duellanten.order_by("liga","-spiele")
    duellanten_liste = []
    if duellant_1.liga == "A":                                            # wenn in der oberste Liga 
        duellanten = duellanten.filter(liga="A")
        for duellant in duellanten:
            duellanten_liste.append(duellant.id)
    else:
        liga_B = duellanten.filter(liga="B").count()
        liga_C = duellanten.filter(liga="C").count()
        if liga_B + liga_C == 0:                                        # es gibt nur eine Liga
            exit
        liga_A = duellanten.filter(liga="A").count()
        for duellant in duellanten:
            duellanten_liste.append(duellant.id)
       
        if duellant_1.liga == "C":
            duellanten_liste = duellanten_liste[-(liga_C+2):]           # die Kandidaten in Liga C plus zwei in Liga B
        else:
            duellanten_liste = duellanten_liste    # die Kandidaten in Liga B plus zwei in Liga A ohne Liga C
    if duellant_1.liga == "A":
        duellant_2 = duellanten.last()                                  # wählt den/die mit den wenigsten Spielen aus
    else:
        duellant_2 = duellanten.get(id = random.choice(duellanten_liste))
    duellant_2.spiele +=1
    duellant_2.punkte_spiel = 0
    duellant_2.save()
    return  duellant_1, duellant_2 

def duell_rang(gruppe_id):
    duellanten = Duellant.objects.filter(profil__gruppe=gruppe_id)
    for duellant in duellanten:
        duellant.punkte +=duellant.punkte_spiel
        duellant.punkte_spiel = 0
        if duellant.spiele != 0:
            duellant.pps = duellant.punkte/duellant.spiele
        duellant.save()
    if duellanten.filter(spiele=0, abwesend=False).count()>0:
        exit
    else:
        for liga in ["A","B","C"]:
            duellanten_liga = duellanten.filter(liga=liga).order_by("-pps","-spiele")
            rang = 0
            pps_speicher = 99
            platz_speicher = 99
            spiele_speicher = 99
            for duellant in duellanten_liga:
                rang +=1
                if duellant.pps == pps_speicher: 
                    if duellant.pps > 0:
                        if duellant.spiele == spiele_speicher:
                            duellant.platz = platz_speicher
                        else:
                            duellant.platz=rang
                    else:
                        duellant.platz = platz_speicher
                else:
                    duellant.platz=rang
                pps_speicher = duellant.pps
                platz_speicher = duellant.platz
                spiele_speicher = duellant.spiele
                duellant.save()

def sub_punkte(req, duell_protokoll, duellant, duellant_nr, eingabe, punkte, beide = False, duell_eingabe = None):
    duellant.punkte_spiel += punkte
    duellant.save()
    if beide != "Zweiter":                                                                    # erstellt nur einen Eintrag in "duell_wertung" (für "Erster")
        protokoll = Protokoll.objects.get(pk = req.session.get('protokoll_id'))
        protokoll.richtig = punkte 
        protokoll.save()
        duell_eingabe = Duell_Eingabe.objects.create(duell_protokoll = duell_protokoll)
        duell_eingabe.eingabe = eingabe
        duell_eingabe.punkte = punkte
        duell_eingabe.duellant_nr = duellant_nr                                               # legt fest ob im Protokoll die Eingabe und der Punkt links oder rechts angezeigt wird
        if beide:
            duell_eingabe.anmerkung = "gleich schnell"
        else:
            duell_eingabe.anmerkung = duellant.name
        duell_eingabe.save()
    return duell_eingabe

def sub_eingabe_speichern(req, duell_protokoll, duellant, eingabe, punkte, beide):
    if beide:
        duellant = duell_protokoll.duellant_1
        duell_eingabe = sub_punkte(req, duell_protokoll, duellant, 2, eingabe, punkte, "Erster" )       
        duellant = duell_protokoll.duellant_2
        sub_punkte(req, duell_protokoll, duellant, 2, eingabe, punkte, "Zweiter")
    else: 
        if duellant.name == duell_protokoll.duellant_1.name:
            duellant_nr = 1
        else:
            duellant_nr = 3
        duell_eingabe = sub_punkte(req, duell_protokoll, duellant, duellant_nr, eingabe, punkte, False )    # übergibt die "duellant_nr", die wird benötigt damit im Protokoll die Eingabe und Punkte links(1) oder rechts(3) zugeordnet werden
    return duell_eingabe

def duell_kontrolle(req):
    meldung = ""
    gruppe = Lerngruppe.objects.get(pk = req.session.get('gruppe_id'))
    if gruppe.lehrer != req.user:
        return HttpResponse("Zugriff verweigert")
    protokoll = Protokoll.objects.get(pk = req.session.get('protokoll_id'))
    protokoll.versuche += 1
    duell_protokoll = Duell_Protokoll.objects.get(pk = req.session.get('duell_id'))
    zaehler = Zaehler.objects.get(user = req.user.profil, kategorie = protokoll.kategorie)

    context = dict()
    #wenn in den Aufgaben in "erg" eine Zahl steht
    if "tab" in protokoll.parameter["name"]:
        # if "term" in protokoll.parameter["name"]:
        #     form = AufgabeFormTerm(req.POST)
        # else:
        form = AufgabeFormTab(req.POST)
    else:
        if protokoll.wert:
            form = AufgabeFormZahl(req.POST)
        #wenn in den Aufgaben erg=None:
        else:
            form = AufgabeFormStr(req.POST)
    #Aufgabe beantwortet
    if form.is_valid():
        # zunächst Einträge im Protokoll:
        if "tab" in protokoll.parameter["name"]:                            # für Wertetabellen
            eingabe = pro_eingabe = str(form.cleaned_data['y5'])
            parser = Parser()
            eingabe=round(round(parser.parse(eingabe.replace(",",".").replace(":","/")).evaluate({}),3),3)
            protokoll.loesung = protokoll.parameter['y5']
            if not protokoll.wert:
                protokoll.loesung = format_zahl(protokoll.parameter['y5'],2)
            #    #protokoll.wert = round(round(parser.parse(protokoll.parameter['y5'].replace(",",".").replace(":","/")).evaluate({}),3),3)
            protokoll.wert = protokoll.parameter['y5']
            protokoll.save()
        else:
            eingabe = pro_eingabe = form.cleaned_data['eingabe']
        req.session['eingabe'] = duell_protokoll.id
        #protokoll.eingabe = pro_eingabe
        protokoll.abbr = False
        protokoll.end = timezone.now()
        protokoll.save()
        #hier wird die Eingabe überprüft:
        wertung, rueckmeldung = kontrolle(eingabe, protokoll.wert, protokoll.loesung, protokoll.id)
        #richtig = wertung
        duellant_name = req.POST.get('duellant')
        if duellant_name == "gleich schnell":
            beide = True 
            duellant = None
        else:
            beide = False
            try:
                duellant = Duellant.objects.get(name=duellant_name)
            except:
                duellant = Duellant.objects.filter(name=duellant_name)
                return HttpResponse("Hier gibt es zwei Duellanten mit gleichem Namen: ", duellant)
        #wenn Eingabe richtig:
        if wertung > 0  :
            if "enauer" in rueckmeldung:
                rueckmeldung = "Die letzte Aufgabe war fast richtig!"+ rueckmeldung
            else:
                rueckmeldung = "Die letzte Aufgabe war richtig!"+ rueckmeldung
            punkte = 1
            duell_eingabe = sub_eingabe_speichern(req, duell_protokoll, duellant, eingabe, punkte, beide)
            if not beide:
                if duell_protokoll.duellant_1.liga != duell_protokoll.duellant_2.liga:                          # zwei verschiedene Ligen
                    if duellant.liga > duell_protokoll.duellant_2.liga:
                        meldung = auf_abstieg(duellant, duell_protokoll.duellant_2)
                        rueckmeldung += "<br>" + meldung
                    elif duellant.liga > duell_protokoll.duellant_1.liga:
                        meldung = auf_abstieg(duellant, duell_protokoll.duellant_1)
                        rueckmeldung += "<br>" + meldung
                    duell_eingabe.anmerkung=meldung
                    duell_eingabe.save()
                else:
                    if duell_protokoll.duellant_1.aufsteiger != duell_protokoll.duellant_2.aufsteiger:          # einer der Duellanten ist Aufsteiger
                    # if (duell_protokoll.duellant_1.aufsteiger or duell_protokoll.duellant_2.aufsteiger) and not (duell_protokoll.duellant_1.aufsteiger and duell_protokoll.duellant_2.aufsteiger):
                        if duell_protokoll.duellant_1.aufsteiger and duellant == duell_protokoll.duellant_2:    # duellant_1 ist aufsteiger, hat verloren und steigt wieder ab
                            meldung = abstieg(duell_protokoll.duellant_1)
                            rueckmeldung += "<br>" + meldung
                        if duell_protokoll.duellant_2.aufsteiger and duellant == duell_protokoll.duellant_1:    # duellant_2 ist aufsteiger, hat verloren und steigt wieder ab
                            meldung = abstieg(duell_protokoll.duellant_2)
                            rueckmeldung += "<br>" + meldung
                        duell_eingabe.anmerkung=meldung
                        duell_eingabe.save()
            messages.info(req, f'{rueckmeldung}')
            zaehler.aufgnr += 1
            zaehler.save()
            if zaehler.aufgnr > 10:
                zaehler.aufgnr = 0
                zaehler.save()                
                return redirect('duell_uebersicht', gruppe.id)
            context['richtig'] = True
        #wenn Aufgabe falsch:
        else:
            if wertung < 0:
                punkte = Decimal(-0.5)
                messages.info(req, f'Die letzte Aufgabe war leider falsch! Versuche: {protokoll.versuche}')#, {msg}') 
            else:
                if not "tab" in protokoll.parameter["name"]:
                    messages.info(req, f'{rueckmeldung}')   #gibt eine Rückmeldung wenn "indiv" bei Lösung steht 
                punkte = Decimal(-0.5)
            sub_eingabe_speichern(req, duell_protokoll, duellant, eingabe, punkte, beide)
        context['falsch'] = True
    farbe_1 = farbe(duell_protokoll.duellant_1.punkte_spiel)
    farbe_2 = farbe(duell_protokoll.duellant_2.punkte_spiel)
    context.update(protokoll = protokoll, duell_protokoll = duell_protokoll, parameter = protokoll.parameter,   
        farbe_1 = farbe_1, farbe_2 = farbe_2, eingabe = eingabe,
        form = form, message_unten = protokoll.anmerkung)
    return render(req, 'duell_aufgabe.html', context)

def auf_abstieg(aufsteiger, absteiger):
    stringwert = ord(aufsteiger.liga)
    aufsteiger.liga = chr(stringwert-1)
    aufsteiger.aufsteiger = True
    aufsteiger.save()
    stringwert = ord(absteiger.liga)
    absteiger.liga = chr(stringwert+1)
    absteiger.aufsteiger = False
    absteiger.save()
    meldung = aufsteiger.name + " steigt auf - " + absteiger.name + " steigt ab"
    return meldung  

def abstieg(absteiger):
    stringwert = ord(absteiger.liga)
    absteiger.liga = chr(stringwert+1)
    absteiger.aufsteiger = False
    absteiger.save()
    meldung = absteiger.name + " steigt wieder ab"
    return meldung  

def farbe(punkte):
    if punkte == 0:
        farbe = "null" 
    elif punkte > 0:
        farbe = "plus" 
    else:
        farbe = "minus"
    return farbe

def duellant_edit(req, duellant_id, punkte):
    duell_protokoll = Duell_Protokoll.objects.get(pk = req.session.get('duell_id'))
    gruppe = get_object_or_404(Lerngruppe, pk=duell_protokoll.gruppe_id)
    if gruppe.lehrer != req.user:
        return HttpResponse("Zugriff verweigert")
    duellant = Duellant.objects.get(id=duellant_id)
    protokoll = Protokoll.objects.get(pk = req.session.get('protokoll_id'))
    #zaehler = Zaehler.objects.get(pk = req.session.get('zaehler_id'))
    duell_eingabe = Duell_Eingabe.objects.create(duell_protokoll = duell_protokoll) 
    if punkte == "plus":
        duellant.punkte_spiel +=Decimal(0.5)
        duell_eingabe.punkte = Decimal(0.5)
    elif punkte == "minus":
        duellant.punkte_spiel -=Decimal(0.5)
        duell_eingabe.punkte = -Decimal(0.5)
    duellant.save()
    duell_eingabe.anmerkung = "edit"
    duell_eingabe.save()
    farbe_1 = farbe(duell_protokoll.duellant_1.punkte_spiel)
    farbe_2 = farbe(duell_protokoll.duellant_2.punkte_spiel)
    if protokoll.wert:
        form = AufgabeFormZahl(req.POST)
    else:
        form = AufgabeFormStr(req.POST)
    context = dict(protokoll = protokoll, duell_protokoll = duell_protokoll, parameter = protokoll.parameter,   
        farbe_1 = farbe_1, farbe_2 = farbe_2,  edit = Protokoll.richtig,
        message_unten = protokoll.anmerkung)
    if protokoll.richtig <= 0: 
        context["form"] = form   
    return render(req, 'duell_aufgabe.html', context)

def duell_protokoll(req, gruppe_id):
    gruppe = Lerngruppe.objects.get(pk = req.session.get('gruppe_id'))
    if gruppe.lehrer != req.user:
        return HttpResponse("Zugriff verweigert")
    else:
        duell_eingabe = Duell_Eingabe.objects.filter(duell_protokoll__gruppe=gruppe).order_by('id').reverse()
        form = DuellProtokollFilter#(
            #     req.POST, req.FILES, gruppe
            # )
        context = dict(duell_eingabe = duell_eingabe, gruppe = gruppe, form = form)
        return render(req, 'duell_protokoll.html', context)
meine templates:
1. Die Aufgabe:

Code: Alles auswählen

{% load static %}
{% load l10n %}

<html lang="de">
<head>       
    <title>Rechentrainer von Peter Doll</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'styles.css' %}">
    <link rel="stylesheet" href="{% static 'core/aufgabe.css' %}">
    <link rel="stylesheet" href="{% static 'duell/duell.css' %}">

    <style>
        input::-webkit-outer-spin-button,
        input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        input[type="number"] {
            -moz-appearance: textfield;
        }
    </style>

    <script>
        let einsStars = "";
        let zweiStars = "";
        let starCount = 0;
        let sekunden = 0
        let uhrInterval;

        // Funktion, um die Uhr zu starten
        function starteUhr() {
            uhrInterval = setInterval(function() {
                sekunden++;
                localStorage.setItem('sekunden', sekunden); // Speichern der Zeit im Local Storage
                document.getElementById('uhr').textContent = sekunden + " Sek.";
            }, 1000); // Update jede Sekunde
        }

        // Funktion, um die Uhr zu stoppen
        function stoppeUhr() {
            clearInterval(uhrInterval); // Stoppe das Intervall
        }

    document.addEventListener('DOMContentLoaded', function() {
        const neu = "{{ neu|default:'' }}"; // Holt den Wert von 'neu' aus dem Template
        const falsch = "{{ falsch|default:'' }}"; // Holt den Wert von 'neu' aus dem Template
        const richtig = "{{ richtig|default:'' }}"; // Holt den Wert von 'neu' aus dem Template
        const edit = "{{ edit|default:'' }}"; // Holt den Wert von 'neu' aus dem Template


        const addStarsInterval = setInterval(function() {
            starCount++;
            einsStars += "*";
            zweiStars += "*";
            document.getElementById('Eins').value = einsStars;
            document.getElementById('Zwei').value = zweiStars;

            // Wenn 4 Sterne erreicht sind, stoppen und sofort die Namen anzeigen
            if (starCount === 4 || falsch || edit || richtig) {
                clearInterval(addStarsInterval);

                // Sofortige Anzeige der Namen und Farben
                document.getElementById('Eins').value = '{{duell_protokoll.duellant_1.name}}';
                document.getElementById('Zwei').value = '{{duell_protokoll.duellant_2.name}}';
                
                // Farben und Meldung sichtbar machen, indem die 'no-color' Klasse durch die Liga-Klassen ersetzt wird
                document.getElementById('Eins').className = '{{ duell_protokoll.duellant_1.liga }}';
                document.getElementById('Zwei').className = '{{ duell_protokoll.duellant_2.liga }}';
                document.getElementById('meldung').textContent = '{{meldung}}';
            }
            }, 500); // Update alle 500 Millisekunden
        
        if (neu) {
            localStorage.clear('sekunden');
            starteUhr();
        }
        else {
            sekunden = localStorage.getItem('sekunden')
            stoppeUhr()
            document.getElementById('uhr').textContent = sekunden + " Sek.";
        }
    });
    </script>
</head>
<body>
    <div class="container">
        {% block content %}
            <div class= "oben">
                <div class="navbar">
                    <a>Duell {{duell_protokoll.gruppe.name}}</a>
                    <a href="{% url 'duell_protokoll' duell_protokoll.gruppe.id %}">Protokoll</a>
                    <a href="{% url 'duell_uebersicht' duell_protokoll.gruppe.id %}">zur Übersicht</a>
                </div>
                {% autoescape off %}
                <div class="message">
                    {% for message in messages %}
                        {% if 'leider falsch' in message.message %}
                            <p class = "rot">{{ message }}</p>
                        {% elif 'halb' in message.message %}
                            <p class = "gelb">{{ message }}</p>
                        {% elif 'war richtig!' in message.message %}
                            <p class = "gruen">{{ message }}</p>
                        {% else %}
                            <p class ="gelb">{{ message }}</p>
                        {% endif%}
                    {% endfor %}
                </div>
                <h2> {{protokoll.titel }}</h2>
                <h3>Aufg. Nr. {{protokoll.aufgnr}}/10 </h3> 
                <h3>{{protokoll.text}} {{protokoll.aufgabe}}</h3>
            </div>
            <div class="mitte">
                <p>
                {% localize off %}
                    {% if parameter.name != "normal" and not "tab" in parameter.name %}
                        {% include parameter.name %} 
                    {% endif %}
                {% endlocalize %}
                </p>
            </div>
            <div class="unten">
                <form action="{% url 'duell_kontrolle' %}" method="POST">
                    {% csrf_token %}
                    <fieldset>
                    {% if "tab" in parameter.name %}
                        {% if lsg %}
                            <table>
                                <tr>
                                    <th class = "linie_rechts">{{parameter.titel_x}}</th>
                                    <th>{{parameter.titel_y}}</th>
                                </tr>
                                {% if parameter.name != "tab_term" %}
                                    <tr>
                                        <td class = "linie_rechts">{{parameter.x0}}</td>
                                        <td>{{parameter.y0}}</td>                                                                       
                                    </tr>
                                    <tr>
                                        <td class = "linie_rechts">{{parameter.x1}}</td>
                                        <td>{{parameter.y1}}</td>                                                                    
                                    </tr>
                                {% endif %}
                                <tr>
                                    <td class = "linie_rechts">{{parameter.x5}}</td>
                                    <td>{{parameter.y5}}</td>                                                                    
                                </tr>
                            </table>
                        {% else %}
                            <table>
                                <tr>
                                    <th class = "linie_rechts">{{parameter.titel_x}}</th>
                                    <th>{{parameter.titel_y}}</th>
                                </tr>
                                {% if 'term' in parameter.name or 'funktion' in parameter.name%}  

                                {% else %}
                                    <tr>
                                        <td class = "linie_rechts">{{parameter.x0}}</td>
                                        <td>{{parameter.y0}}</td>                                                                       
                                    </tr>
                                    <tr>
                                        <td class = "linie_rechts">{{parameter.x1}}</td>
                                        <td>{{parameter.y1}}</td>                                                                    
                                    </tr>
                                {% endif %}
                                <tr>
                                    <td class = "linie_rechts">{{parameter.x5}}</td>
                                    {% if richtig %}
                                        <td>{{eingabe}}</td>
                                    {% else%}
                                        <td class = "{{parameter.color2}}">{{form.y5}}</td>
                                    {% endif %} 
                                </tr>
                            </table>
                        {% endif %}
                    {% else %}
                        <div class = "fett">
                            {% if richtig %}
                                Eingabe:
                                {{protokoll.frage}}
                                {{eingabe}}
                                {{protokoll.einheit}}
                            {% else %}
                                {{protokoll.frage}}
                                {{form.eingabe}}
                                {{protokoll.einheit}}
                            {% endif %}
                        </div>
                    {%endif%}
                    <script>
                        document.getElementById('id_eingabe').addEventListener('keypress', function(event) {
                            if (event.keyCode == 13) {
                                event.preventDefault();
                            }
                        });
                    </script>
                    <h2 id="meldung" style="text-align: left";></h2>
                        <table>
                            <tr>
                                {% if richtig %}
                                    <td class = {{duell_protokoll.duellant_1.liga}} style = "height: 35px; width: 280px;font-weight: bold;" >{{duell_protokoll.duellant_1.name}}</td>
                                {% else %}
                                    <td><input type="submit" id="Eins" name = "duellant" class="no-color" value=""  ></td>
                                {% endif %} 
                                <td>{{aufsteiger_1}}</td>
                                <td class = "{{farbe_1}}">{{duell_protokoll.duellant_1.punkte_spiel}}</td>
                                {% if not neu %}
                                    <td class = "minus"><a href="{% url 'duellant_edit' duell_protokoll.duellant_1.id "minus" %}">-</a></td>
                                    <td class = "plus"><a href="{% url 'duellant_edit' duell_protokoll.duellant_1.id "plus" %}">+</a></td>
                                {%endif%}
                            </tr>
                            <tr>
                                {% if richtig %}
                                    <td class = "null">gleich schnell</td>
                                {% else %}
                                    <td><input type="submit" name = "duellant" value="gleich schnell" style = "background-color: #FFDEAD;"></td></tr>                                    
                                {% endif %}
                            <tr>
                                {% if richtig %}
                                    <td class = {{duell_protokoll.duellant_2.liga}} style = "height: 35px; width: 280px;font-weight: bold;" >{{duell_protokoll.duellant_2.name}}</td>
                                {% else %}
                                    <td><input type="submit" id="Zwei" name = "duellant" class="no-color" value=""  ></td>
                                {% endif %} 
                                <td>{{aufsteiger_2}}</td>
                                <td class = "{{farbe_2}}">{{duell_protokoll.duellant_2.punkte_spiel}}</td>
                                {% if not neu %}
                                    <td class = "minus"><a href="{% url 'duellant_edit' duell_protokoll.duellant_2.id "minus" %}">-</a></td>
                                    <td class = "plus"><a href="{% url 'duellant_edit' duell_protokoll.duellant_2.id "plus" %}">+</a></td>
                                {%endif%}
                            </tr>
                        </table>
                    </fieldset>
                </form>
                <p></p>
                <table>
                    <tr><td>
                        <button type="button">
                            <a style= "font-weight: bold;" href="{% url 'duell_aufgabe' protokoll.kategorie.slug %}">nächste Aufgabe</a>
                        </button>
                    </td>
                    <td  class="zeitfeld null" id="uhr">0</td>
                    <td>
                        <button type="button">
                            <a href="{% url 'duell_uebersicht' duell_protokoll.gruppe.id %}">Abbrechen</a>
                        </button>
                    </td></tr>
                    {% if not richtig %}
                        <tr><td>
                            <button type="button" >
                                <a href="{% url 'neu_auslosen' "mit" %}">neue Kandidaten mit Punktabzug</a>
                            </button>
                        </td><td>
                            <button type="button">
                                <a href="{% url 'neu_auslosen' "ohne"  %}">neue Kandidaten ohne Punktabzug</a>
                            </button>
                        </td><td>
                            <button type="button">
                                <a href="{% url 'duell_loesung'  %}">Lösung</a>
                            </button>
                        </td></tr>
                    {% endif %}
                </table>
            {% endautoescape %}
        {% endblock %}
    </div>
</body>
Die Übersicht:

Code: Alles auswählen

<!DOCTYPE html>
{% load static %}

<html lang="de">
<head>       
    <title>Rechentrainer im Web</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="{% static 'styles.css' %}">
    <link rel="stylesheet" href="{% static 'duell/duell_uebersicht.css' %}">
</head>

<header>
    <div class="navbar">
        <a href="{% url 'index' %}">&#8962 Home</a>
        <a>Rechenduell {{gruppe}}</a>
        <a href="{% url 'duell_how_to' %}">Wie funktioniert das Duell?</a>
        <a href="{% url 'duell_protokoll' gruppe_id %}">Protokoll</a>
        <a href="javascript:history.go(-1)" class="btn btn-default">zurück</a>
    </div> 
</header>
<br>
    <body>
        <div class="container">
            {% comment %} <div class="message">
                {% for message in messages %}
                    {% if 'leider falsch' in message.message %}
                        <p class = "rot">{{ message }}</p>
                    {% elif 'halb' in message.message %}
                        <p class = "gelb">{{ message }}</p>
                    {% elif 'war richtig!' in message.message %}
                        <p class = "gruen">{{ message }}</p>
                    {% else %}
                        <p class ="gelb">{{ message }}</p>
                    {% endif%}
                {% endfor %}
            </div> {% endcomment %}
            <button type="button">
                {% if dubletten_liste %}
                    Diese(n) Namen gibt es mehrfach: {{dubletten_liste}}<br>Bitte jeweils durch Klick auf den Namen umbenennen.
                {% elif leerstellen_liste %}
                    Diese(n) Namen enthalten Leerstellen: {{leerstellen_liste}}<br>Bitte Leerstelle entfernen oder z.B. durch einen Unterstrich ersetzen.
                {% else %}
                    <a href="{% url 'duell_start' gruppe_id %}">Duell Start</a>
                {% endif %}
            </button> 
            <p></p>  
            <form action="/duell_uebersicht/{{gruppe_id}}/" method="POST">
                {% csrf_token %}
                <table>
                    <thead>
                        <tr>
                            <th >Liga</th>
                            <th >↑</th>
                            <th >Platz</th>
                            <th width= "200px">Name</th>
                            <th >Spiele</th>
                            <th >Punkte</th>
                            <th >PPS</th>
                            <th >abwesend</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tr>
                    {% for duellant in duellanten %}
                        <tr class = {{duellant.liga}}>
                            <td>{{duellant.liga}}</td>
                            <td>{% if duellant.aufsteiger %}↑{%else%}{%endif%}</td>
                            <td>{% if duellant.platz %}{{duellant.platz}}{%else%}{%endif%}</td>
                            <td style="text-align: left"; ><a  class="button" href="{% url 'duellant_aendern' gruppe_id duellant.id %}">{{duellant.name}}</a></td>
                            <td>{{duellant.spiele}}</td>
                            <td>{{duellant.punkte}}</td>
                            <td>{{duellant.pps}}</td>
                            <td>
                                {% if duellant.abwesend%}
                                    <input class="form-check-input" type="checkbox" value={{duellant.id}} name="ID" checked>
                                {%else%}
                                    <input class="form-check-input" type="checkbox" value={{duellant.id}} name="ID" >
                                {%endif%}
                            </td>
                        </tr>
                    {% empty %}
                        <tr><td colspan="999"><strong>Es sind noch keine Schüler angemeldet.</strong></td></tr>
                    {% endfor %}
                    <tr>
                        <td colspan="4"><button><a href="{% url 'duell_loeschen' %}">Duell löschen</a></button></td>
                        {% comment %} <td >
                            <form method="post" action="{% url 'duell_loeschen' %}">
                                {% csrf_token %}
                                <a><input type="submit"  value= "loeschen"></a>
                            </form>
                        </td> {% endcomment %}
                        <td colspan="3"><label >Abwesende speichern</label></td> 
                        <td><input type="submit" name="abwesend" value="übernehmen" ></td>
                    </tr>
                    </tbody>
                </table>

            </form>

        </div>
    </body>
</html>
das Protokoll:

Code: Alles auswählen

{% extends 'layout.html' %}
{% load static %}
{% block css_files %}
    <link rel="stylesheet" href="{% static 'core/protokoll.css' %}">
    <link rel="stylesheet" href="{% static 'duell/duell.css' %}">

{% endblock %}

{% block content %}
<header>
    <div class="navbar">
        <a href="{% url 'index' %}">&#8962 Home</a>
        <a>Protokoll Rechenduell {{gruppe.name}} {{gruppe.lehrer.profil.vorname}} {{gruppe.lehrer.profil.nachname}}</a>
        <a href="javascript:history.go(-1)" class="btn btn-default">zurück</a>
    </div> 
</header>
<body>
    {% comment %} <form action="{% url 'duell_protokoll' gruppe.id %}" method="POST">
        {% csrf_token %}
        {{form}}
        <input type="submit" value="anwenden">
    </form> {% endcomment %}

    <div class="container">
        <table>
            <thead>
                <tr>
                    <th>Datum</th>
                    <th>Kategorie</th>
                    <th>Aufgnr.</th>
                    <th>Aufgabe</th>
                    <th>Ergebnis</th>
                    {% comment %} <th>r/f</th> {% endcomment %}
                    <th>Duellant 1</th>
                    <th>Liga</th>
                    <th></th>
                    <th>Eingabe</th>
                    <th>Punkte</th>
                    <th>Duellant 2</th>
                    <th>Liga</th> 
                    <th></th> 
                    <th>Eingabe</th>
                    <th>Punkte</th>
                    <th></th>                      
                </tr>
            </thead>
            <tbody>
                {% autoescape off %}
                {% for zeile in duell_eingabe %}
                    <tr>
                        <td>{{zeile.duell_protokoll.protokoll.start|date:"d.m. H:i"}}</td>
                        <td>{{zeile.duell_protokoll.protokoll.kategorie.name }} <br>({{zeile.duell_protokoll.protokoll.typ}})</td>
                        <td>{{zeile.duell_protokoll.protokoll.aufgnr}} </td>
                        {% if zeile.anmerkung != "edit" %} 
                            {% if zeile.duell_protokoll.protokoll.pro_text != ""  %}
                                <td>{{ zeile.duell_protokoll.protokoll.pro_text}}</td>
                            {% else %}
                                <td>{{zeile.duell_protokoll.protokoll.text}}</td>
                            {% endif%}
                            <td>{%if zeile.duell_protokoll.protokoll.wert%}
                                    {{zeile.duell_protokoll.protokoll.wert.normalize}}
                                {%else%}
                                    {{zeile.duell_protokoll.protokoll.loesung.0}}
                                {%endif%}
                            </td>
                                {% comment %} <td class = "{{zeile.duell_protokoll.protokoll.farbe}}">{{ zeile.duell_protokoll.protokoll.richtig.normalize}}</td> {% endcomment %}
                            {% else %}
                                <td></td><td></td>
                            {% endif %}                            
                        <td class = {{zeile.duell_protokoll.duellant_1.liga}}>{{ zeile.duell_protokoll.duellant_1.name}}</td>                
                        <td class = {{zeile.duell_protokoll.duellant_1.liga}}>{{ zeile.duell_protokoll.duellant_1.liga}}</td>
                            {% if zeile.duell_protokoll.duellant_1.aufsteiger %}
                                <td class = {{zeile.duell_protokoll.duellant_1.liga}}>↑</td>
                            {% else %}
                                <td></td> 
                            {% endif %}
                        </td>
                        {% if zeile.duellant_nr < 3%} 
                            {% if zeile.anmerkung != "edit" %} 
                                <td class = "{{zeile.farbe}}">{{zeile.eingabe}}</td>
                            {% else %}
                                <td></td>
                            {% endif %}
                            <td class = "{{zeile.farbe}}">{{zeile.punkte}}</td>
                        {% else %}
                            <td></td> 
                            <td></td> 
                        {% endif %}
                        <td class = {{zeile.duell_protokoll.duellant_2.liga}}>{{zeile.duell_protokoll.duellant_2.name}}</td>                
                        <td class = {{zeile.duell_protokoll.duellant_2.liga}}>{{zeile.duell_protokoll.duellant_2.liga}}</td>
                        {% if zeile.duell_protokoll.duellant_2.aufsteiger %}
                            <td class = {{zeile.duell_protokoll.duellant_2.liga}}>↑</td>
                        {% else %}
                            <td></td>  
                        {% endif %}
                        {% if zeile.duellant_nr > 1%}
                            {% if zeile.anmerkung != "edit" %} 
                                <td class = "{{zeile.farbe}}">{{zeile.eingabe}}</td>
                            {% else %}
                                <td></td>
                            {% endif %}
                            <td class = "{{zeile.farbe}}">{{zeile.punkte}}</td>
                        {% else %}
                            <td></td> 
                            <td></td> 
                        {% endif %}
                        <td>{{zeile.anmerkung}}</td>
                    </tr>
                {% empty %}
                    <strong>Leider keine Kategorien vorhanden.</strong> 
                {% endfor %}
                {% endautoescape %}
            </tbody>
        </table>
    </body>
</div>
{% endblock %}

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

Noch ein Nachtrag. Das:
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Insgesamt macht der ganze Code wenig Sinn.
ist schon sehr überheblich. Ich bin dir sehr dankbar für deine Hilfe. Aber hier brauche ich schon ein gesundes Selbstvertrauen um weiterzumachen. Ich kann dir sicher beim Programmieren nicht das Wasser reichen. Ich habe aber fast 8 Wochen an meinem Rechenduell gearbeitet. es funktioniert bis auf diese blöde Anzeige des Punktes, meine Nutzer sind sehr angetan. So eine Aussage ist sehr demotivierend und eigentlich richtig gemein.
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Nachdem ich nochmal über dieses Problem geschlafen habe, habe ich wohl auch eine Lösung gefunden. Ich glaube nicht, dass ihr da noch drüber hirnen müsst. ich nehme die "punkte_spiel" aus dem "Duell_Protokoll" und packe sie in "Duell_Wertung" und addiere hier auch nicht die Punkte, sondern setze sie als feste Werte.
Aber ich habe noch zwei Fragen:
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Klassen schreibt man als CamelCase ohne Unterstriche. Die Groß-Klein-Schreibung trennt ja schon einzelne Wörter.
Wo findet man diese Festlegungen wie man was schreibt? Und "CamelCase" kommt von den Kamelhöckern?
Sirius3 hat geschrieben: Dienstag 27. August 2024, 20:36 Ich würde ja erwarten, dass es einen "status" gibt, der entweder den Wert "richtig" oder "falsch" hat.
Wie würdest du diesen Status speichern? Als Cookie in der Session? Oder gibt es da noch andere Möglichkeiten?
Und noch was Grundlegendes:
Ich erneuere ja in meinen Views normalerweise das ganze Template, gibt es auch die Möglichkeit innerhalb eines Templates nur einen Teilbereich neu zu schreiben?
Benutzeravatar
Dennis89
User
Beiträge: 1503
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen,

die Richtlinien für die Schreibweisen und auch noch weitere findest du hier:
https://peps.python.org/pep-0008/

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pitwheazle: CamelCase ist im Deutschen die Binnenmajuskel — manchmal ist das ganz gut wenn Fachbegriffe nicht übersetzt werden. 😉

Der englischsprachige Wikipediaartikel hat dieses nette Bild: Bild

Offtopic: Das Originalkamel ist eine SVG-Grafik, das hier ist ein Screenshot von einem Chip16-Emulator. Das SVG-Bild in Inkscape als PNG exportiert, mit GIMP in ein Bild mit einer Palette von 16 Farben umgwandelt, und dann mit folgendem Python-Programm ein ROM für den Emulator daraus gebastelt:

Code: Alles auswählen

#!/usr/bin/env python3
from PIL import Image

VIEWER_LISTING = """\
0000 01 00 00 00  CLS
0004 D0 00 1C 00  PAL palette
0008 04 00 A0 F0  SPR 160, 240
000C 20 00 00 00  LDI R0, 0
0010 20 01 4C 00  LDI R1, sprite
0014 06 00 01 00  DRW R0, R0, R1
0018 10 00 18 00  JMP *
"""
# 001C ... 16x3 bytes RGB palette
# 004C ... 38400 bytes sprite data
# 964C End of ROM


def main():
    #
    # Expects a 320×240 indexed image with a 16 color palette.
    # 
    image = Image.open("camelcase.png")
    assert image.mode == "P"
    assert len(image.getpalette()) == 16 * 3
    assert image.size == (320, 240)

    with open("output.bin", "wb") as file:
        file.write(
            bytes.fromhex(
                " ".join(line[5:16] for line in VIEWER_LISTING.splitlines())
            )
        )
        file.write(bytes(image.getpalette()))
        pixels = iter(image.getdata())
        file.write(
            bytes(
                (pixel_a << 4 | pixel_b)
                for pixel_a, pixel_b in zip(pixels, pixels)
            )
        )


if __name__ == "__main__":
    main()
Das simple Anzeige-Programm ist ohne Assembler entstanden. Die Chip16-Maschinenbefehle sind ja supersimpel aufgebaut.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

@dennis89 Vielen Dank - was es nicht alles gibt! (Ist das nicht alles etwas spießig?)
@__blackjack__ Sehr schön!
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

Nein, das ist nicht spießig. Da Python weitestgehend Freiheiten bei der Benennung und eingeschränkt bei der Formatierung gewährt, bedarf es entsprechender Konventionen. So etwas gibt es für fast alle Programmiersprachen. Sie sorgen dafür, dass Code zwischen Emtwicklern möglichst einfach auszutauschen ist. Unforcierte Regeln. Umfeld ja in es anderen gibt auch.
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn das nicht ”von oben” oder ”aussen” festgelegt wird, dann gehen regelmässig Diskussionen los. Man mag manchmal gar nicht glauben wie viel Zeit man dafür verbraten kann zu diskutieren wo die geschweiften Klammern bei C-ähnlichen Programmiersprachen hinkommen. Und das nicht allgemein für alle, sondern für Strukturen/Klassen, Funktionen, Schleifen, ``if``-Anweisungen, und ``switch``/``case`` getrennt. Drei Programmierer, fünf Meinungen. Und zwar erbittert hart verteidigte Meinungen.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

abgesehen davon ist die PEP8 der weithin akzeptierte und umgesetzte "heilige Gral" der Python Programmierung. Wenn man ernsthaft in Python programmieren will sollte man die zumindest 1x gelesen haben und sich weitestgehend daran halten. Zumindest die ganzen grundlegenden Sachen wie Namenskonventionen etc.

Gruß, noisefloor
nezzcarth
User
Beiträge: 1733
Registriert: Samstag 16. April 2011, 12:47

Pitwheazle hat geschrieben: Mittwoch 28. August 2024, 22:06 @dennis89 Vielen Dank - was es nicht alles gibt! (Ist das nicht alles etwas spießig?)
Mich wundert, dass dich das nach all der Zeit hier im Forum und mit Python scheinbar wundert. Pep-8 wird zum Beispiel im offiziellen Python Tutorial, das jeder Mal am Anfang seiner Python-Karriere durchgearbeitet haben sollte, in Kapitel 4.9 angesprochen.
Zuletzt geändert von nezzcarth am Donnerstag 29. August 2024, 17:52, insgesamt 1-mal geändert.
Pitwheazle
User
Beiträge: 1050
Registriert: Sonntag 19. September 2021, 09:40

Der Anfang meiner Python Karriere war ein Buch und das in Django einTutorium in udemy - aber ich hole das nach
Antworten