Ist Django für mein Projekt geeignet?

Django, Flask, Bottle, WSGI, CGI…
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Ohne jetzt deinen Code im Kontext anzusehen:

Die Rückgabe von Prokoll.objects.all() sagt nichts über die Reihenfolge der Objekte, die geliefert werden. Du kannst dich also nicht darauf verlassen, dass das [zeile_id]te Element das Element ist, das du haben willst.
Du brauchst also etwas anderes, womit du das entsprechende Protokoll findest. Am besten seine id. Und die fragst du dann enstprechend mit get ab. Oder noch besser mit dem get_or_404 shortcut.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Und bitte Code als Text in Code-Tags hier im Forum posten und nicht als Bilder.
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Wahrscheinlich so:

Code: Alles auswählen

def detail(req, zeile_id):
    protokoll = get_object_or_404(Protokoll, pk=zeile_id)
    ...
Gruß
Whitie
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Montag 7. März 2022, 23:08 Und bitte Code als Text in Code-Tags hier im Forum posten und nicht als Bilder.
Das habe ich nur ausnahmsweise gemacht damit ich die Ausschnitte einkringeln kann.
Whitie hat geschrieben: Dienstag 8. März 2022, 06:57 Wahrscheinlich so:

Code: Alles auswählen

def detail(req, zeile_id):
    protokoll = get_object_or_404(Protokoll, pk=zeile_id)
    ...
Gruß
Whitie
Funktioniert einwandfrei. Auch hier wieder: Tausend Dank.
Das frustriert mich aber auch gleichzeitig. Kann nicht bitte einer von euch mal ein Buch zu Django schreiben. Ich kann doch nicht bei jedem Problem euch hier belästigen. Ich war es gewohnt mithilfe eines Buches mir z.B. das Programmieren von StarBasic beizubringen. Bei Django muss ich immer wieder in irgendwelchen Onlinetutorien suchen. Besonders schlimm ist es, wenn diese auch noch als Filme angeboten werden und man dann elend lang braucht bis man eventuell eine Stelle findet, die weiterhilft. Und dazu muss man natürlich noch wissen nach was man überhaupt suchen muss. Oh man! Und möglicherweise vergesse ich dann das eine oder andere auch wieder (Demenz) und ich muss nochmal suchen.
sparrow hat geschrieben: Montag 7. März 2022, 22:46 Ohne jetzt deinen Code im Kontext anzusehen:

Die Rückgabe von Prokoll.objects.all() sagt nichts über die Reihenfolge der Objekte, die geliefert werden. Du kannst dich also nicht darauf verlassen, dass das [zeile_id]te Element das Element ist, das du haben willst.
Du brauchst also etwas anderes, womit du das entsprechende Protokoll findest. Am besten seine id. Und die fragst du dann enstprechend mit get ab. Oder noch besser mit dem get_or_404 shortcut.
Der rechte Eintrag "zeile_id" zeigt die ID doch richtig an, warum wird die ID im linken Eintrag "zeile_id" nicht weitergereicht? Frust!
Bild
Warum gibt mir dann

Code: Alles auswählen

protokoll = Protokoll.objects.all()[zeile_id]
nicht das richtige Objekt zurück? Es gibt mir ja eins zurück, aber nicht das richtige.
Benutzeravatar
__blackjack__
User
Beiträge: 13063
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Die letzte Frage wurde doch schon beantwortet. `all()` liefert eine Sequenz und der Index ist halt nicht die ID. Selbst wenn die beispielsweise aufsteigend sortiert wären, kann man ja auch Lücken in den IDs haben, die dann aber nicht Lücken in der Sequenz entsprächen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass man get_object_or_404 benutzen soll, steht im offiziellen Django-Tutorial drin. Das sollte man einmal durchgearbeitet haben, bevor man mit eigenen Projekten anfängt. Es gibt einfach zu viel, was man einmal gesehen haben muß, sonst verrennt man sich irgendwo.
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

Da mir jetzt noch keiner geschrieben hat ich solle das Handbuch lesen, traue ich mich jetzt auch weiter zu fragen:
@whitie hat mir ja ein Grundgerüst geschrieben (ansonsten hätte ich das Projekt wahrscheinlich aufgegeben) und zum Lernen habe ich das etwas ergänzt. (Um die einzelnen Funktionen besser zu verstehen, habe ich Stück für Stück, Teile durch Teile mit deutscher Benennung erstezt. Dieser View hier ist wohl der Knotenpunkt um den sich alles dreht und den möchte ich jetzt entgültig verstehen und ergänzen:

Code: Alles auswählen

def aufgabe(req, modul_id):
    modul = get_object_or_404(Kategorie, pk=modul_id)
    if req.method == 'POST':
        protokoll = Protokoll.objects.get(pk=req.session.get('eingabe_id'))
        protokoll.tries += 1
        #zaehler=Zaehler.objects.filter(user=protokoll.user, kategorie=modul.id)
        form = AufgabeFormZahl(req.POST)
        right=protokoll.value
        if form.is_valid():
            if kontrolle(form.cleaned_data['eingabe'], right):
                protokoll.eingabe=form.cleaned_data['eingabe']
                protokoll.bearbeitungszeit=(timezone.now() - protokoll.start).total_seconds()
                protokoll.save()
                min, sec = divmod(protokoll.bearbeitungszeit, 60)
                msg = f'Zeit: {int(min)}min {int(sec)}s'
                messages.info(req, f'Richtig! Versuche: {protokoll.tries}, {msg}')
                return redirect('modul', modul_id)
        messages.info(req, 'Leider falsch.')
        protokoll.eingabe=form.cleaned_data['eingabe']
        protokoll.save()
        text = protokoll.text
    else:
        frage = Frage.objects.filter(
            kategorie=modul
        ).order_by('?').first()
        form = AufgabeFormZahl()
        user=get_fake_user()
        zahl1, zahl2, result =aufgabenstellung(modul_id, user.jahrgang) 
        text = frage.aufgabe.format(zahl1=zahl1, zahl2=zahl2)
        protokoll = Protokoll.objects.create(
            user=user, kategorie=modul, text=text, value=result, loesung=str(result)         
        )
        zaehler, created = Zaehler.objects.get_or_create(
            user=user,
            kategorie=modul,
        )   
        req.session['eingabe_id'] = protokoll.id
    context = dict(category=modul, text=text, aufgabe=aufgabe, form=form)
    return render(req, 'core/aufgabe.html', context)
Bitte sagt mir doch, ob ich das soweit richtig verstanden habe:
  • Nach der Auswahl der Kategorie (z.B. "addieren") wird dieser View aufgerufen und die ID der Kategorie übergeben.
    Das Objekt "addieren" im modul "Kategorien" wird aufgerufen.
    Dann Sprung zu "else"
    Die Aufgabe wird erstellt.
    Ein neues Protokoll Objekt wird erstellt.
    Ich habe dann versucht zu überprüfen, ob es ein Objekt zu "Zaehler" mit dem user und der Kategorie gibt und hoffe, dass, wenn nicht, eines erstellt wird.
    Dann wird die Seite aufgerufen.
2. Frage: was genau macht "req.session['eingabe_id'] = protokoll.id"?
  • Dann macht der user eine Eingabe.
    Der Code springt zu " if req.method == 'POST':".
    Aus dem Protokoll wird der Eintrag zur richtigen Lösung ausgelesen.
    Die Eingabe wird überprüft.
    Je nachdem ob richtig oder falsch werden die Einträge im Protokoll ergänzt.
3. Frage: Wie funktioniert der Aufruf "protokoll = Protokoll.objects.get(pk=req.session.get('eingabe_id'))" genau?
4. Frage: Was macht "return redirect('modul', modul_id)"
5. Frage: Wie kann ich hier wieder auf mein vorher erstelltes Objekt "zaehler" zugreifen?

Und die 1. Frage, stimmt meine Interpretation so?
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

__blackjack__ hat geschrieben: Dienstag 8. März 2022, 13:21 Die letzte Frage wurde doch schon beantwortet. `all()` liefert eine Sequenz und der Index ist halt nicht die ID. Selbst wenn die beispielsweise aufsteigend sortiert wären, kann man ja auch Lücken in den IDs haben, die dann aber nicht Lücken in der Sequenz entsprächen.
Das mit den Lücken ist klar. Im view "index" werden ja die Einträge mit "tries=0" gelöscht. Und ich kann im Protokoll ja auch die Lücken sehen, da ich ja (vorübergehend) die ID des Eintrags anzeigen lasse. Es interessiert mich aber trotzdem welches Objekt denn in meinem Beispiel aufgerufen wird - ich habe keine Logik erkennen können, außer dass die im "Detail" angezeigte Zeile eine höhere ID hat als die gewünschte und dass der Abstand immer größer wird.
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Dienstag 8. März 2022, 13:50 Dass man get_object_or_404 benutzen soll, steht im offiziellen Django-Tutorial drin. Das sollte man einmal durchgearbeitet haben, bevor man mit eigenen Projekten anfängt. Es gibt einfach zu viel, was man einmal gesehen haben muß, sonst verrennt man sich irgendwo.
Ja, stimmt, das steht am Ende von Teil 3. Ich habe parallel ja zwei Videotutorien bearbeitet und mein neu gelerntes Wissen immer versucht gleich in mein Projekt einzubauen. Dadurch dass ich die Inhalte jeweils anpassen muss, verstehe ich das Gelernte besser und ich habe außerdem die Befürchtung, dass ich den Anfang wieder vergessen habe, wenn ich zunächst die Tutorien bis zum Ende durcharbeite (siehe: Demenz). Aber es stimmt, ich habe mit meinem Projekt jetzt im Überschwang die Inhalte des Tutoriums überholt.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Es gibt keine Logik, wie die Reihenfolge der Objekte ist, die mit `all` zurückgeliefert wird. all liefert einfach nur alle Objekte; die Reihenfolge ist nicht definiert. Es ist übrigens Verschwendung, sich alle Objekte geben zu lassen, obwohl man nur eins braucht.
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

OK!
Das geht wohl auch nicht:

Code: Alles auswählen

protokoll=Protokoll.objects.filter(zeile_id)
?
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

So:

Code: Alles auswählen

protokoll=Protokoll.objects.filter(pk=zeile_id)
Das wäre aber schlecht, da es nur ein Objekt mit der ID geben kann. Besser dann so:

Code: Alles auswählen

protokoll=Protokoll.objects.get(pk=zeile_id)
oder gleich:

Code: Alles auswählen

protokoll=get_object_or_404(Protokoll, pk=zeile_id)
Gruß
Whitie
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Wenn du keinen Fehler 404 liefern willst, sondern irgendwie anders reagieren willst:

Code: Alles auswählen

try:
    protokoll = Protokoll.objects.get(pk=zeile_id)
except Protokoll.DoesNotExist:
   # tu was bei Fehler
Falls das Objekt erzeugt werden soll, wenn es noch nicht existiert: https://docs.djangoproject.com/en/4.0/r ... -or-create

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

Beim Protokoll kann es ja meines Erachtens nicht vorkommen, dass das Objekt nicht existiert. Aber bei meinem Zähler hatte ich (nach der obigen Anleitung (die hatte ich tatsächlich vorher schon gefunden)) das geschrieben (siehe oben):

Code: Alles auswählen

       zaehler, created = Zaehler.objects.get_or_create(
            user=user,
            kategorie=modul,
        ) 
oder ist das so richtig:

Code: Alles auswählen

        try:
            zaehler = Zaehler.objects.get(user=user, kategorie=modul)
        except zaehler.DoesNotExist:
            obj = Zaehler(user=user, kategorie=modul)
            obj.save()
        ) 
... der Unterschied ist mir nicht ganz klar. Meines Erachtens, kann dieses Objekt doch auch nur einmalig erzeugt werden - und das erste Beispiel ist kürzer.

Und dazu noch diese Frage. In deinem Code erstellst du ein Protokoll Objekt auf dass du weiter oben im Code wieder zugreifst wenn die Schülereingabe überprüft wurde. Ich nehme an, um dieses Objekt zu kennzeichen dient die letzte Zeile:

Code: Alles auswählen

        protokoll = Protokoll.objects.create(
            user=user, kategorie=modul, text=text, value=result, loesung=str(result)         
        )
        req.session['eingabe_id'] = protokoll.id
Ich habe mich an den Erklärungen mit den Sessions versucht, diese aber in diesem Zusammenhang nicht verstanden. Kannst du mir da auf die Sprünge helfen?
Ich würde ja, wie in deinem Code, nach der Überprüfung der Eingabe auch auf mein Zaehler Objekt zugreifen, das gelingt mir aber noch nicht.
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

(Leider kann ich meinen Beitrag nicht ändern):
Der zweite Teil hat sich erledigt, ich habe etwas rumprobiert und es hinbekommen (nur mit euren prima Anregungen)
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Bei den beiden oberen Beispielen gibt es keinen Unterschied. Das erste ist ein Shortcut für das zweite. Haben die Django Entwickler eingebaut, weil man es häufig braucht.
Pitwheazle
User
Beiträge: 871
Registriert: Sonntag 19. September 2021, 09:40

Danke. Vielleicht habe ich daher den Unterschied in der Erklärung im Handbuch nicht verstanden. Die erste Version soll verhindern, dass ein Objekt doppelt angelegt wird - oder so.
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

Das verhindern beide Versionen explizit dadurch, dass sie eben einen vorhandenen Eintrag updaten oder einen neuen erstellen.
Und beide werfen auch einen Fehler, falls es mehr als einen vorhandenen Eintrag gibt.
Antworten