Ist Django für mein Projekt geeignet?

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

Code: Alles auswählen

{% include {{grafik.name|urlencode}} %}
geht auch nicht, obwohl der Link ordentlich angezeigt wird:
Bild

Code: Alles auswählen

<p>{{grafik.name|urlencode}}</p>
{% if grafik.name %}
    {% include "svg/zahlenstrahl.svg" %} 
    {% comment %} {% include {{grafik.name|urlencode}} %} {% endcomment %}
{% endif %}
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Was habe ich denn hier wieder nicht verstanden:

Da das mit den Dictionaries so gut funktioniert, wollte ich jetzt auch mehrere Lösungen als Liste übergeben. Nehmen wir als Beispiel die Aufgaben "kleiner, größer oder gleich". In der Funktion erstelle ich eine Liste

Code: Alles auswählen

lsg = [("kleiner"), ("<")]
die übergebe ich mit

Code: Alles auswählen

return typ, text, "", lsg, hilfe, erg, grafik
speichere sie in "protokoll.loesung" und rufe sie dann in der Funktion "loesung" auf.

Code: Alles auswählen

msg=protokoll.loesung
    # print(msg)
gibt "['kleiner', '<']" aus.
Ich will jetzt aber z.B. nur das erste Element

Code: Alles auswählen

    msg_t=protokoll.loesung[0]
    print(msg_t)
gibt aber "[", das erste Zeichen meiner vermeintlichen Liste aus.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pitwheazle: Das sieht so aus als hättest Du die Liste irgendwo in eine Zeichenkette umgewandelt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Spannende Frage: wo?
Erzeugt wird die (vermeintliche) Liste in der Funktion "zahlen":

Code: Alles auswählen

            if zahl1 < zahl2:
                lsg = [str(zahl1) + "<" +  str(zahl2), "<"]
            elif zahl1 > zahl2:
                lsg = [str(zahl1) + ">" +  str(zahl2), ">"]
            else:
                lsg = [str(zahl1) + "=" +  str(zahl2), "="]
und dann (wie beschrieben) weitergegeben mit:

Code: Alles auswählen

return typ, text, "", anm, lsg, hilfe, erg, grafik
Aufgerufen wird die Funktion "zahlen" aus der Funktion "main":

Code: Alles auswählen

typ, text, pro_text, anm, lsg, hilfe, result, grafik = aufgaben(kategorie.id, jg = user.jg, stufe = user.stufe, typ_anf = zaehler.typ_anf, typ_end = zaehler.typ_end, optionen = "") 
und danach wird der Wert (u.A.) in dem Model "protokoll" im Feld "loesung" gespeichert:

Code: Alles auswählen

    loesung = models.CharField(max_length=100, blank=True, verbose_name="Lösung")

Code: Alles auswählen

        protokoll = Protokoll.objects.create(
            user = user, kategorie = kategorie, text = text, pro_text = pro_text, anmerkung = anm, value = result, loesung = lsg, hilfe = hilfe, grafik = grafik       
        ) 
und bei Klick auf "Lösung anzeigen" auf der HTML Seite wird die Funktion "loesung" aufgerufen:

Code: Alles auswählen

def loesung(req, zaehler_id):
    ...
    protokoll = Protokoll.objects.filter(user = zaehler.user).order_by('-id').first()
    #msg=f'{protokoll.text} Lösung: {protokoll.loesung}' 
    msg = protokoll.loesung
    print(msg)
    ....

Lässt sich der Fehler in diesen Codeteilen erkennen?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Du speicherst Deine Liste in einem Feld vom Typ CharField.
Komplexere Objekte kann man zum Beispiel json-kodieren, um sie in eine Datenbank zu schreiben.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Pitwheazle hat geschrieben: Sonntag 3. Juli 2022, 12:50 Da das mit den Dictionaries so gut funktioniert, wollte ich jetzt auch mehrere Lösungen als Liste übergeben.
... da bin ich wohl übermütig geworden. Ich übergebe mit "grafik" ja auch die Parameter für meine Grafiken und speichere sie in einem CharField:

Code: Alles auswählen

    grafik = models.CharField(max_length=400, blank=True)
... das funktioniert. Dann dachte ich, dass müsste auch mit einer Liste funktionieren (Das würde ein paar Zeichen sparen).
OK, dann mache ich auch ein Dictonary aus den Lösungen. Ich würde bei der Auswertung halt gerne eine Schleife mit "if loesung in liste" abarbeiten.
Ich frage jetzt mal ganz dumm: Die Ausgabe, die ich in der HTML Seite angezeigt bekomme (und auch mit print(loesung)) sieht doch wie eine Liste aus. Eigentlich müsste man doch auch wieder eine Liste draus erstellen können. Woher weiß Pyzthon den dass dieser String ein String ist und keine Liste (auch wenn er wie eine Liste aussieht)?
JSON habe ich mich etwas eingelesen, sehe jetzt aber keinen Vorteil gegenüber einem Dictonary - oder habe ich da auch wieder was übersehen?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Python ist es egal, wie das für Dich aussieht, es weiß, dass der Wert von CharField ein String ist, was da drin ist, ist egal.
Und wenn Du Dictionaries richtig behandelst, dann müssen die auch erst kodiert werden, um sie in ein CharField zu schreiben, und dafür ist nunmal JSON üblich, und zum Decodieren in eine Liste oder ein Wörterbuch braucht man json.decode. Der Vorteil ist also, dass es funktioniert, im Gegensatz zu Deinen andern "Lösungen", die nicht funktionieren.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

OK. Dann muss ich mich genauer mit JSON beschäftigen! Danke!
Ich habe auch festgestellt, dass ich auf die einzelnen Parameter von "grafik" (die ich ja als Dictionary erzeuge und als Charfield abspeichere) zwar in meinem svg Code ansprechen kann - nicht aber im Python Code. Bisher benötige ich die auch nur im svg Code - siehst du da Probleme, wenn ich das so belasse?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie schaffst Du es denn, eine Stringrepräsentation eines Wörterbuchs in svg anzusprechen? Für das Template-System von django brauchst Du doch ein Wörterbuch.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Dann muss ich mich genauer mit JSON beschäftigen!
Das gute ist, dass sich die meisten Datenstrukturen quasi 1:1 in Python abbilden lassen, von daher ist das ziemlich einfach.

Django unterstützt ja seit ein paar Version das JSONField (Link) direkt für diverse DBs, von daher kann man das ruhig nutzen.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Montag 4. Juli 2022, 14:04 Wie schaffst Du es denn, eine Stringrepräsentation eines Wörterbuchs in svg anzusprechen? Für das Template-System von django brauchst Du doch ein Wörterbuch.
Für meinen Zahlenstrahl definiere ich:

Code: Alles auswählen

    grafik = {'name': 'zahlenstrahl', 'anf': anf, 'eint':eint, 'txt0':  z+(v-1)*z, 'txt1': z+v*z, 'txt2': z+(v+1)*z, 'txt3': z+z*(v+2), 'txt4': z+z*(v+3), 'text_v': text_v, 'x': int(zahl1+anf)}
        return typ, text, "", anm, lsg, hilfe, erg, grafik 
... das rufe ich, wie oben schon beschrieben in der Fuunktion "main" auf und speichere es in einem Charfield in meinem model "protokoll:

Code: Alles auswählen

        typ, text, pro_text, anm, lsg, hilfe, result, grafik = aufgaben(kategorie.id, jg = user.jg, stufe = user.stufe, typ_anf = zaehler.typ_anf, typ_end = zaehler.typ_end, optionen = "") 
        protokoll = Protokoll.objects.create(
            user = user, kategorie = kategorie, text = text, pro_text = pro_text, anmerkung = anm, value = result, loesung = lsg, hilfe = hilfe, grafik = grafik       
        )
übergebe es an mein Template:

Code: Alles auswählen

    context = dict(kategorie = kategorie, typ = protokoll.typ, aufgnr = zaehler.aufgnr, text = protokoll.text, anmerkung = protokoll.anmerkung, form = form, zaehler_id = zaehler.id, hilfe = protokoll.hilfe, protokoll_id = protokoll.id, grafik = protokoll.grafik)
    return render(req, 'core/aufgabe.html', context)
und in meinem Template funktioniert

Code: Alles auswählen

{% if grafik.name %}
    {% include "svg/zahlenstrahl.svg" %} 
{% endif %}
einwandfrei und fügt meine Grafik nur ein, wenn ein Name unter "grafik.name" hinterlegt ist und auch z.B.

Code: Alles auswählen

		<!--Beschriftung-->	
		{% if grafik.txt0 == 0 %}
			<text x={{grafik.text_v|add:17}} y="95" style="url(#text)">{{grafik.txt0}}</text>
		{% else %}
			<text x={{grafik.text_v|add:7}} y="95" style="url(#text)">{{grafik.txt0}}</text>
		{% endif %}
		<text x={{grafik.text_v|add:107}} y="95" style="url(#text)">{{grafik.txt1}}</text>
		<text x={{grafik.text_v|add:207}} y="95" style="url(#text)">{{grafik.txt2}}</text>
		<text x={{grafik.text_v|add:307}} y="95" style="url(#text)">{{grafik.txt3}}</text>
		<text x={{grafik.text_v|add:407}} y="95" style="url(#text)">{{grafik.txt4}}</text>
funktioniert auch wie gewünscht.
Ich könnte mir jetzt aber, nachdem du sagst, das könne so nicht funktionieren, vorstellen, dass

Code: Alles auswählen

context = dict(... grafik = protokoll.grafik)
die Werte nicht aus der Datenbank zieht sondern von "typ, text, pro_text, anm, lsg, hilfe, result, grafik = aufgaben(..." übernimmt, oder von " protokoll = Protokoll.objects.create(... grafik = grafik)
... das würde auch erklären, dass die Grafik bei der ersten Erzeugung angezeigt wird, nicht aber bei einer Falscheingabe. Bei dieser wird die letzte Aufgabe aus dem Protokoll geladen und angezeigt - nicht aber die Grafik! Dann wäre noch ein Geheimnis gelöst!
OK, dann versuche ich mich mal an JSON!
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Hallo Leute - ich bräuchte euch mal wieder:
Hier möchte ich hinter "Aufgaben Halbjahr" die Werte drunter aufsummieren - aber wie?
Bild
Der Ausschnitt aus meinem Code des Templates:

Code: Alles auswählen

...
    <tbody>
        <td>Aufgaben Halbjahr</td>
        <td>-</td>
        <td>-</td>
        <td>-</td>
        <td>-</td>
        <td>-</td>  
        <td>-</td>
        <td>-</td>

        {% for zeile, zaehler in kategorien %}
        <tr>
        <td><a class="button" href="{% url 'main' zeile.slug %}">{{zeile.name|title}}</th>
            {% if zaehler %}
                <td>{{zaehler.richtig}}</td>                    
                <td>{{zaehler.falsch}}</td>
               ...
                <td>{{zaehler.richtig_of}}/{{zeile.eof}}</td>
                <td>{{zaehler.abbrechen}}</td>
                <td>{{zaehler.loesung}}</td>
                <td>{{zaehler.hilfe}}</td>
                ...
reichen euch diese Infos?
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

nicht so richtig.... Djangos Template Engine kennt den add-Filter, mit dem man addieren kann. Aber wenn man in irgendeiner Form Werte aggregieren möchte, dann macht man das ggf. besser direkt bei der Abfrage der Datenbank und übergibt den Wert dem Template.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Parallel brauche ich diese Summe auch für meine Protokoll Seite. Davor müsste ich die Daten aber erst filtern. Mir ist es immerhin schon gelungen, eine Form mit Auswahlmöglichkeiten zu erzeugen (ohne euch zu fragen - ich bin ganz stolz!):
Bild
Jetzt weiß ich nicht so recht, wie ich an die entsprechende Auswahl komme.
Der Code im Template:

Code: Alles auswählen

<form action="{% url 'protokoll' %}" method="post">
    {% csrf_token %}
    <label for="auswahl">Filter:</label>
    <select id="auswahl">
        <option value="heute">heute</options>
        <option value="Wo">Woche</options>
        <option value="Hj">aktuelles Halbjahr</options>
        <option value="Sj">aktuelles Schuljahr</options>
        <option value="all">Alles</options>
     </select>
     <input class="button-primary" type="submit" value="anwenden">
</form>  
und im view:

Code: Alles auswählen

def protokoll(req):
    if req.method == 'POST':
        form = "auswahl"(req.POST)
        if form.is_valid():     
            filter = form.cleaned_data['auswahl']
            print(filter)
    protokoll = Protokoll.objects.all().order_by('id').reverse()
    user = get_fake_user()    
    return render(req, 'core/protokoll.html', {'protokoll': protokoll})
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

noisefloor hat geschrieben: Sonntag 10. Juli 2022, 15:05 Aber wenn man in irgendeiner Form Werte aggregieren möchte, dann macht man das ggf. besser direkt bei der Abfrage der Datenbank und übergibt den Wert dem Template.
Gruß, noisefloor
Danke! Dann werde ich mich mal dran versuchen.
("aggregieren" kannte ich noch nicht :o )

Nachtrag:
Aggregieren kann ich wohl auch nicht!
Die Werte von denen ich die Summen will, finden sich im Model "Zaehler" unter "richtg", "falsch" usw.
ich habe es so probiert:

Code: Alles auswählen

def uebersicht(req):
    user = get_fake_user()
    summe = Zaehler.objects.filter(user=user)
    summe_richtig = summe.richtig.count()
    print(summe_richtig)

    kategorien = []
    for kategorie in Kategorie.objects.all():
        zaehler = Zaehler.objects.filter(user=user, kategorie=kategorie).first()
        kategorien.append((kategorie, zaehler))
    return render(req, 'core/uebersicht.html', {'kategorien': kategorien, 'user':user})
Aber das geht nicht:
'QuerySet' object has no attribute 'richtig'
(In Erinnerung von whities Hinweis, was ich immer mit den Punkten will, habe ich es auch mit

Code: Alles auswählen

summe_richtig = summe__richtig.count()
probiert.)
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

So, tun tut es jetzt. Aber irgendwie sieht das bei mir noch nicht so elegant aus. Kann man das auch einfacher schreiben:

Code: Alles auswählen

def uebersicht(req):
    user = get_fake_user()
    summe = Zaehler.objects.filter(user=user)
    summe.count()
    summe = Zaehler.objects.filter(user=user)
    richtig = summe.aggregate(Sum('richtig'))
    richtig = richtig['richtig__sum']
    falsch = summe.aggregate(Sum('falsch'))
    falsch = falsch['falsch__sum']
    if richtig+falsch > 0:
        quote = int(falsch/(richtig+falsch)*100)
    else:
        quote = "-"
    abbr = summe.aggregate(Sum('abbrechen'))
    abbr = abbr['abbrechen__sum']
    lsg = summe.aggregate(Sum('loesung'))
    lsg = lsg['loesung__sum']
    hilfe = summe.aggregate(Sum('hilfe'))
    hilfe = hilfe['hilfe__sum']

    kategorien = []
    for kategorie in Kategorie.objects.all():
        zaehler = Zaehler.objects.filter(user=user, kategorie=kategorie).first()
        kategorien.append((kategorie, zaehler))
    return render(req, 'core/uebersicht.html', {'kategorien': kategorien, 'user':user, 'richtig':richtig, 'falsch':falsch, 'quote':quote, 'abbr':abbr, 'lsg':lsg, 'hilfe': hilfe})
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Pitwheazle hat geschrieben: Sonntag 10. Juli 2022, 15:11 ... für meine Protokoll Seite. Davor müsste ich die Daten aber erst filtern.
OK, das ist mir jetzt auch gelungen!
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Ich bastele jetzt an meinem Filter für das Protokoll. Ich möchte, wenn "heute" ausgewählt wird, nur die Daten vom heutigen Tag. Im Model "protokoll" ist das Datum in einem DateTimeField gespeichert. Das kann ich auch auslesen, aber wie bekomme ich nur das Datum? "filter(start.date() = date.today())" funktioniert nicht.
Mein Code:

Code: Alles auswählen

def protokoll(req):
    user = get_fake_user()    
    protokoll = Protokoll.objects.filter(user=user).order_by('id').reverse()
    form = ProtokollFilter
    if req.method == 'POST':
        auswahl = form(req.POST)
        if auswahl.is_valid():     
            filter = auswahl.cleaned_data['filter']
            print(filter)
            if filter == "heute":
                print(protokoll[0].start)
                print(protokoll[0].start.date())
                print(date.today())
                #heute =  protokoll.filter(start.date() = date.today())
    return render(req, 'core/protokoll.html', {'protokoll': protokoll, 'form': form})
und die Ausgabe:

Code: Alles auswählen

heute
2022-07-13 12:28:18.102325+00:00
2022-07-13
2022-07-13
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Nachtrag:
anscheinend funktioniert

Code: Alles auswählen

protokoll =  protokoll.filter(start__startswith = date.today())
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

na ja, das ist aber keine saubere Lösung...
"filter(start.date() = date.today())" funktioniert nicht.
Kann eigentlich auch nicht funktionieren. Hat `start` überhaupt eine `date` Methode?

Ungetestet:

Code: Alles auswählen

protokoll.filter(start__date=datetime.date.today())
Siehe Doku: Link.

Gruß, noisefloor
Antworten