Seite 1 von 1

Formatierungsprobleme

Verfasst: Sonntag 26. Februar 2023, 18:28
von Pitwheazle
Ich habe mir eure Hinweise zu Herzen genommen und die Zugriffe auf meine Daten umgestellt und habe jetzt zwei Fragen:
Meine Übersicht sieht jetzt so aus:
Bild
Die Einträge "True" und "False" kommen von meiner Summe über "Abbrechen", "Lösung anzeigen" und "Hilfe anzeigen". "False" wird angezeigt, wenn kein Eintrag gefunden wird, "True" bei einem und ansonsten die Summe. Gibt es eine einfache Möglichkeit, "0" und "1" anzuzeigen oder muss ich das immer mit "if" und "elseif" abfangen?

Code: Alles auswählen

            abbr_gesamt = protokoll.aggregate(Sum('abbr'))['abbr__sum']
            lsg_gesamt = protokoll.aggregate(Sum('lsg'))['lsg__sum']
            hilfe_gesamt = protokoll.aggregate(Sum('hilfe'))['hilfe__sum']
Und dann müsste ich über alle Einträge in "Protokoll" die Gesamtzeit aus den Einträgen "start" und "end" bilden.
@sparrow: Du hast mir das mal so zusammengebastelt (und das tut auch an der Stelle, wofür du es geschrieben hast.I
sparrow hat geschrieben: Sonntag 19. Februar 2023, 21:18 Das Gruppieren und Annotieren kann die Datenbank übernehmen. Und wir verwenden eine F-Expression um die Zeit auszurechnen:

Code: Alles auswählen

from django.db.models import F, Sum

protkoll_statistics = (
    Protokoll.objects
    .values("user__name", "kategorie__name")
    .annotate(richtig_sum=Sum('richtig'))
    .annotate(falsch_sum=Sum('falsch'))
    .annotate(zeit_sum=Sum(F('end') - F('start')))
    .order_by()
) 
Ich habe auch den Link zu den f-expressions geöffnet und versucht zu verstehen - hier klappt es aber nicht:

Code: Alles auswählen

            protokoll = Protokoll.objects.filter(user=user, sj=user.sj, hj=user.hj)
            zeit_gesamt = protokoll.aggregate(Sum(F('end') - F('start')))
wirft den Fehler:

Code: Alles auswählen

Complex aggregates require an alias
- was mache ich damit?

Re: Formatierungsprobleme

Verfasst: Sonntag 26. Februar 2023, 21:01
von Whitie
Hallo,
falls ich dich richtig verstanden habe, könnte ein "yesno" Filter evtl. dein Problem lösen.

Die Fehlermeldung sagt, du sollst einen Alias für die Summe setzen. Evtl. so (kenne mich damit aber eher weniger aus):

Code: Alles auswählen

zeit_gesamt = protokoll.annotate(fulltime=Sum(F('end') - F('start')))
Viele Grüße
Whitie

Edit: Ist das "Sum" da nicht überflüssig?

Re: Formatierungsprobleme

Verfasst: Sonntag 26. Februar 2023, 21:02
von geraldfo
Die Darstellung von True/False kannst du mit diesem yesno-Dings abändern:
https://docs.djangoproject.com/en/stabl ... ins/#yesno

Re: Formatierungsprobleme

Verfasst: Montag 27. Februar 2023, 18:07
von Pitwheazle
geraldfo hat geschrieben: Sonntag 26. Februar 2023, 21:02 Die Darstellung von True/False kannst du mit diesem yesno-Dings abändern:
https://docs.djangoproject.com/en/stabl ... ins/#yesno
Putzig! Wo zaubert ihr nur immer wieder die Kaninchen her? (Allerdings hatte ich das auch schon mal gelesen - aber wieder aus dem Auge/Sinn verloren).
Das funktioniert aber leider nicht, weill ich die Werte aus einer Liste auslese und dann nur noch Einsen und Nullen auftauchen:

Code: Alles auswählen

                    {% for style, item in zeile %}
                        <td class = "{{style}}">{{item}}</td>
                    {% endfor %}
... da muss ich wohl doch die if/elifs im View setzen.
Whitie hat geschrieben: Sonntag 26. Februar 2023, 21:01 Die Fehlermeldung sagt, du sollst einen Alias für die Summe setzen. Evtl. so (kenne mich damit aber eher weniger aus):

Code: Alles auswählen

zeit_gesamt = protokoll.annotate(fulltime=Sum(F('end') - F('start')))
Edit: Ist das "Sum" da nicht überflüssig?
Also so, wie er dasteht, gibt "zeit_gesamt" ein queryset mehrerer Protokollobjekte zurück und ohne "sum" kann er mit "fulltime" nix anfangen. Wie soll ich das definieren?

Re: Formatierungsprobleme

Verfasst: Montag 27. Februar 2023, 20:59
von Whitie
Also wenn deine Nullen und Einsen Zahlen sind (keine Zeichenketten), sollte der yesno-Filter funktionieren. Sonst könntest du dir einen eigenen Filter schreiben.

Mit yesno:

Code: Alles auswählen

{% for style, item in zeile %}
    <td class = "{{ style }}">{{ item|yesno:"0,1" }}</td>
{% endfor %}
Für das Summieren musst du auf einen Experten warten, damit hab ich nur selten gearbeitet. Habe erstmal keine Idee dazu.

Viele Grüße
Whitie

Re: Formatierungsprobleme

Verfasst: Dienstag 28. Februar 2023, 15:04
von Pitwheazle
Ich bestimme ja die Bearbeitungszeit für jede einzelne Kategorie und summiere das jetzt einfach auf.

Und da ich auch Zeichenketten in meiner Liste habe, ändere ich jetzt die False/True doch per if/elif im view:

Code: Alles auswählen

                    abbr_kat = k['abbr']
                    if not abbr_kat:
                        abbr_kat = 0
                    elif abbr_kat == True:
                        abbr_kat = 1
                    lsg_kat = k['lsg'] 
                    if not lsg_kat:
                        lsg_kat = 0
                    elif lsg_kat == True:
                        lsg_kat = 1
                    hilfe_kat = k['hilfe']
                    if not hilfe_kat:
                        hilfe_kat = 0
                    elif hilfe_kat == True:
                        hilfe_kat = 1
 
Ich frage mich, warum das so nicht geht:

Code: Alles auswählen

                     for z in ["abbr_kat", "lsg_kat", "hilfe_kat"]:
                         if not z:
                             z = 0
                         elif z == True:
                             z = 1  

Re: Formatierungsprobleme

Verfasst: Dienstag 28. Februar 2023, 16:07
von __blackjack__
Na weil keine dieser Zeichenketten leer ist und keine dieser Zeichenketten die ganze Zahl 1 oder der Wahrheitswert `True` ist. Das ist sowieso schräg das `z` mal an eine Zeichenkette und mal an die ganzen Zahlen 0 und 1 gebunden werden soll.

Re: Formatierungsprobleme

Verfasst: Dienstag 28. Februar 2023, 16:07
von Sirius3
Keine Ahnung, wo Du dieses Code-Fragment wieder eingebaut hast. Aber das Problem liegt daran, dass die "richtig"-Spalte vom Typ Boolean ist und bei 0 bis 1 Summanden das ein Boolean bleibt, und erst bei mehreren Einträgen in ein int konvertiert wird. Deshalb mußt Du den Wert casten:

Code: Alles auswählen

protkoll_statistics = (
    Protokoll.objects
    .values("user__name", "kategorie__name")
	.annotate(
		richtg_as_int=Cast('richtig', output_field=IntegerField()),
		falsch_as_int=Cast('falsch', output_field=IntegerField())
	).annotate(
		richtig_sum=Sum('richtg_as_int'),
		falsch_sum=Sum('falsch_as_int'),
		zeit_sum=Sum(F('end') - F('start'))
	).order_by()
)

Re: Formatierungsprobleme

Verfasst: Dienstag 28. Februar 2023, 18:49
von Pitwheazle
Sirius3 hat geschrieben: Dienstag 28. Februar 2023, 16:07 Keine Ahnung, wo Du dieses Code-Fragment wieder eingebaut hast. Aber das Problem liegt daran, dass die "richtig"-Spalte vom Typ Boolean ist und bei 0 bis 1 Summanden das ein Boolean bleibt, und erst bei mehreren Einträgen in ein int konvertiert wird. Deshalb mußt Du den Wert casten:
Das Code_fragment ist von @sparrows (siehe oben).
Der Rest sieht so aus:

Code: Alles auswählen

        for kategorie in kategorien:
            index =  kategorie.zeile
            protokoll_kategorie = protokoll.filter(kategorie = kategorie.id)
            if protokoll_kategorie.count() > 0:                        # es sind Aufgaben da
                zaehler_kategorie = Zaehler.objects.get(user=user, kategorie = kategorie)
                kategorie_werte = (                                    # die Summen der einzelnen Kategoren des jeweiligen Users
                    protokoll_kategorie
                    .values("kategorie__zeile")
                    .annotate(richtig_sum=Sum('richtig'))
                    .annotate(falsch_sum=Sum('falsch'))
                    .annotate(zeit_sum=Sum(F('end') - F('start')))
                    .annotate(abbr=Sum('abbr'))
                    .annotate(lsg=Sum('lsg'))
                    .annotate(hilfe=Sum('hilfe'))
                    )
                for k in kategorie_werte:
                    zeile = [[],[]] 
                    richtig_kat = k['richtig_sum']
                    falsch_kat = k['falsch_sum']
                    qfarbe = quote_farbe(richtig_kat, falsch_kat)
                    zeit_kat = k['zeit_sum']
                    if richtig_kat+falsch_kat > 0:
                        quote = int(falsch_kat/(richtig_kat+falsch_kat)*100)
                        pro_aufg = round(zeit_kat.total_seconds()/float(richtig_kat+falsch_kat),1)
                    else:
                        quote = "-"
                        pro_aufg = "-"
                    abbr_kat = k['abbr']
                    if not abbr_kat:
                        abbr_kat = 0
                    elif abbr_kat == True:
                        abbr_kat = 1
                    lsg_kat = k['lsg'] 
                    if not lsg_kat:
                        lsg_kat = 0
                    elif lsg_kat == True:
                        lsg_kat = 1
                    hilfe_kat = k['hilfe']
                    if not hilfe_kat:
                        hilfe_kat = 0
                    elif hilfe_kat == True:
                        hilfe_kat = 1
... und liefert, wie du beschreibst 0, 1, oder die entsprechende Summe. Und ich "dachte" mal wieder, anstelle von dreimal if/elif, könnte man das abkürzen. Da oben, mit den drei if/elifs funktioniert es ja auch wie gewünscht. Aber wenn ich dich richtig verstehe, kann ich das im obigen Code schon weiter vorne einbauen (Und mal "casten" nachschlagen).

Re: Formatierungsprobleme

Verfasst: Dienstag 28. Februar 2023, 22:05
von Pitwheazle
Mann, mann, mann! Auf Entfernung gesehen ist das ja zu blöd! Ich denke das liegt am Alter und die Hirnleistung (Demenz?) lässt nach.(Ich habe das "Denken" ja auch in Anführungszeichen gesetzt.) Ist hier noch jemand im Rentenalter?
Klar "for z in ["abbr_kat", "lsg_kat", "hilfe_kat"]:" betrifft nur die Strings. Aber wie wäre es denn mit:

Code: Alles auswählen

                    for z in [abbr_kat, lsg_kat, hilfe_kat]:
                        if not z:
                            z = 0
                        elif z == True:
                            z = 1  
... oder ist das auch blödsinnig? (Funktioniert übrigens auch nicht)

Re: Formatierungsprobleme

Verfasst: Dienstag 28. Februar 2023, 22:58
von Sirius3
Wie ich schon geschrieben habe, wandelt man den Datentyp bereits beim Abfragen der Daten um.
Gäbe es diese Möglichkeit nicht, würde man einfach `int` verwenden:

Code: Alles auswählen

abbr_kat = int(k['abbr'])

Re: Formatierungsprobleme

Verfasst: Mittwoch 1. März 2023, 18:13
von Pitwheazle
Sirius3 hat geschrieben: Dienstag 28. Februar 2023, 22:58 Wie ich schon geschrieben habe, wandelt man den Datentyp bereits beim Abfragen der Daten um.
Gäbe es diese Möglichkeit nicht, würde man einfach `int` verwenden:

Code: Alles auswählen

abbr_kat = int(k['abbr'])
Das funktioniert ja auch wunderbar und würde meine ursprüngliche Fragestellung unkompliziert beantworten.
Wo ist den jetzt der Vorteil von:
Sirius3 hat geschrieben: Dienstag 28. Februar 2023, 16:07 ...Deshalb mußt Du den Wert casten:

Code: Alles auswählen

protkoll_statistics = (
    Protokoll.objects
    .values("user__name", "kategorie__name")
	.annotate(
		richtg_as_int=Cast('richtig', output_field=IntegerField()),
		falsch_as_int=Cast('falsch', output_field=IntegerField())
	).annotate(
		richtig_sum=Sum('richtg_as_int'),
		falsch_sum=Sum('falsch_as_int'),
		zeit_sum=Sum(F('end') - F('start'))
	).order_by()
)
... und dann wäre es prima, wenn du mir den Code noch genauer erklären könntest.
Warum zwei ".values("user__name", "kategorie__name")" und warum zwei annotate Einträge - der zweite scheint ja auf dem ersten aufzubauen?
Mein Code sieht zum Vergleich jetzt so aus:

Code: Alles auswählen

        for kategorie in kategorien:
            index =  kategorie.zeile
            protokoll_kategorie = protokoll.filter(kategorie = kategorie.id)
            if protokoll_kategorie.count() > 0:                        # es sind Aufgaben da
                zaehler_kategorie = Zaehler.objects.get(user=user, kategorie = kategorie)
                kategorie_werte = (                                    # die Summen der einzelnen Kategoren des jeweiligen Users
                    protokoll_kategorie
                    .values("kategorie__zeile")
                    .annotate(richtig_sum=Sum('richtig'))
                    .annotate(falsch_sum=Sum('falsch'))
                    .annotate(zeit_sum=Sum(F('end') - F('start')))
                    .annotate(abbr=Sum('abbr'))
                    .annotate(lsg=Sum('lsg'))
                    .annotate(hilfe=Sum('hilfe'))
                    )
                for k in kategorie_werte:
                    zeile = [[],[]] 
                    richtig_kat = k['richtig_sum']
                    falsch_kat = k['falsch_sum']
                    qfarbe = quote_farbe(richtig_kat, falsch_kat)
                    zeit_kat = k['zeit_sum']
                    abbr_kat = int(k['abbr'])
                    lsg_kat = int(k['lsg']) 
                    hilfe_kat = int(k['hilfe'])
... wobei ich auch noch wirklich verstanden hebe, warum ich die Werte, die "annotate" liefert, mit "for k in kategorie_werte" ausgelesen werden müssen und ich nicht direkt darauf zu greifen kann.