Ist Django für mein Projekt geeignet?

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

In dem Fall würde ich sagen, dass sich die Klassenstufe nicht aus der Klassenbezeichnung zwangsläufig ableiten lässt. Und das würde bedeuten, dass beides voneinander getrennt ins Model gehört einmal der Name, einmal auswählbar die Klassenstufe.
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Hallo, da bin ich wieder mal. Es wäre schön, wenn ihr mir wieder weiterhelfen könntet:
Um den Code, den @whitie in 1 1/2 Stunden aufgesetzt hat, (größtenteils) nachzuvollziehen, habe ich jetzt 1 1/2 Monate gebraucht (manchmal zwei Tage für eine Zeile) und wollte jetzt mal drangehen, meine Aufgaben zu programmieren.
Die URL

Code: Alles auswählen

path('modul/<int:modul_id>/', views.aufgabe, name='modul'),
ruft den view

Code: Alles auswählen

def aufgabe(req, modul_id):
    modul = get_object_or_404(Kategorie, pk=modul_id)
    if req.method == 'POST':
        daten = Daten.objects.get(pk=req.session.get('eingabe_id'))
        daten.tries += 1
        form = AufgabeFormZahl(req.POST)
        right=daten.value
        if form.is_valid():
            if check_str(form.cleaned_data['eingabe'], right):
                daten.eingabe=form.cleaned_data['eingabe']
                daten.bearbeitungszeit=(timezone.now() - daten.start).total_seconds()
                daten.save()
                min, sec = divmod(daten.bearbeitungszeit, 60)
                msg = f'Zeit: {int(min)}min {int(sec)}s'
                messages.info(req, f'Richtig! Versuche: {daten.tries}, {msg}')
                return redirect('modul', modul_id)
        messages.info(req, 'Leider falsch.')
        daten.eingabe=form.cleaned_data['eingabe']
        daten.save()
        text = daten.text
    else:
        frage = Frage.objects.filter(
            kategorie=modul
        ).order_by('?').first()
       form = AufgabeFormZahl()

       low, high, result = make_zahl(modul_id)
       
       text = frage.text.format(low=low, high=high)
       daten = Daten.objects.create(
            user=get_fake_user(), kategorie=modul, text=text, value=result, loesung=str(result)         
        )
        req.session['eingabe_id'] = daten.id
    context = dict(category=modul, text=text, aufgabe=aufgabe, form=form)
    return render(req, 'core/aufgabe.html', context)
(von Whitie) auf.
Für die Zeile "low, high, result = make_zahl(modul_id)" brauche ich jetzt eine Verzweigung für meine 35 Aufgabenarten. Es gibt doch sicher eine elegantere Verzweigungsmöglichkeit als "if modul_id==1: ...., elif ... elif ... ". Ich denke ja an 35 Funktionen (die könnte ich im Editor auch einklappen um den Code übersichtlicher zu halten). Wie rufe ich aber jetzt 35 verschiedene Funktionen möglichst elegant auf?
Sirius3
User
Beiträge: 18264
Registriert: Sonntag 21. Oktober 2012, 17:20

Elegant wäre, statt einer modul_id einen sprechenden Namen zu haben und dann ein Wörterbuch zu benutzen.

Code: Alles auswählen

def addition():
    return "was ist 3+4?", 7

def multiplikation():
    return "was ist 5*5?", 25

AUFGABEN = {
    "addition": addition,
    "multiplikation": multiplikation,
}

def aufgabe(modul_id):
    return AUFGABEN[modul_id]()

def main():
    text, loesung = aufgabe("multiplikation")
    if float(input(text)) == loesung:
        print("richtig")
    else:
        print("falsch")

if __name__ == "__main__":
    main()
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Hallo @Sirius3,
vielen Dank für die blitzschnelle Antwort. Kannst du da einem blutigen Anfänger bitte noch etwas weiterhelfen?
Also die ersten zwei Funktionen sind klar, das sind Funktionen, die entweder eine Additions- oder Multiplikationsaufgabe erstellen.
Dann kommt das Wörterbuch mit meinen 35 Aufgabentypen.
Die dritte Funktion wird von der URL aufgerufen und ordnet der modul_id einen Namen zu, das ist schon mal prima.

Aber dann verließen sie ihn.
Die vierte Funktion erzeugt eine Multiplikationsaufgabe und überprüft die Eingabe. ... und wo kommt die Verzweigung zum Tragen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Verzweigung erfolgt durch das nachschlagen der gewünschten Funktion im Wörterbuch, und den danach erfolgenden Aufruf.
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Das mit dem Wörterbuch habe ich verstanden. Ich tue mich aber immer noch schwer mich in den Rest einzudenken und erkenne noch nicht wie bzw. wo genau die Funktionen "addition" bzw. "multiplikation" aufgerufen werden. Könnt ihr mir das bitte Schritt für Schritt aufzeigen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da:

AUFGABEN[modul_id]()

Die ()-Klammern sind der Aufruf.
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Danke, wahrscheinlich muss ich das jetzt mal ausprobieren.

Mich verwirrt, dass in def main() ... "multiplikation" steht. Wie komme ich an "addition"?

Bleibt mein Pfad "path('modul/<int:modul_id>/', views.aufgabe, name='modul')" so stehen oder muss ich den in "path('modul/<int:modul_id>/', views.main, name='modul')" ändern?

Ich hoffe ihr habt noch etwas Geduld mit mir - war bei euch der Anfang auch so schwer?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist im Beispiel ja nur illustriert. Wenn du da Addition schreibst, gibt’s eben Addition. Wenn du das per Kommandozeile angebracht machst, dann kommt’s eben daher. Und wenn es ein Teil eines URL-Pfades ist, dann eben daher. Ich bin mit Django nicht genug Perdu um da sagen auch können, ob du da was anders machen musst.
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Ah, ja, das ist wieder sehr erhellend. Ich muss also eine Möglichkeit finden, dieses "multiplikation" dynamisch mit der "modul_id" zu ersetzen. Das müsste ja, glaube ich, auch mit dem Key des Wörterbuchs gehen.

Und wofür dient das "if __name__ == "__main__":" in deinem Beispiel? Ich habe es in mehreren Tutorien und Erläuterungen gefunden, diese gelesen, in englisch und in deutsch - ich habe es aber immer noch nicht kapiert. (Zum Beispiel hier https://www.data-science-architect.de/__name____main__/ - da hat sich Andreas Wygrabek echt Mühe gegeben). Vielleicht hilft es mir, wenn du es hier konkret am Beispiel erklärst.
Benutzeravatar
Whitie
User
Beiträge: 217
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Wenn du bei deiner ID bleiben willst, z. B.:

Code: Alles auswählen

def addition():
    return "was ist 3+4?", 7

def multiplikation():
    return "was ist 5*5?", 25

AUFGABEN = {
    1: addition,
    2: multiplikation,
}
Wenn du es etwas sprechender magst:

Code: Alles auswählen

path('modul/<modul_name>/', views.aufgabe, name='modul')

def aufgabe(req, modul_name):
    modul = get_object_or_404(Kategorie, name=modul_name)
    ...
Dazu muss das Model natürlich ein Attribut name haben und das sollte unique=True haben.

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

Das mit dem unique=True muss ich erst noch verarbeiten.
Aber ohne dich würde ich drüber nachdenken, ob ich anstelle von meinem Ringen mit Python doch lieber endlich mal damit anfangen sollte meine Socken zu stopfen (das Projekt wartet auch noch auf mich,)
Benutzeravatar
Whitie
User
Beiträge: 217
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Das unique bedeutet nur, dass die Datenbank schon darauf achtet, dass der Name einmalig ist. Da der Name gleichzeitig ein Schlüssel im Wörterbuch ist, sollte das auf jeden Fall so sein. Man könnte dann den Namen auch als Primärschlüssel nutzen, ich lasse aber immer die ID als numerischen Primärschlüssel.
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Hurra, das funktioniert!

Code: Alles auswählen

AUFGABEN = {
    1: ergaenzen,
    2: addieren,
    3: subtrahieren,
}

def aufgabenstellung(modul_id):
    return AUFGABEN[modul_id]()

def aufgabe(req, modul_id):
    modul = get_object_or_404(Kategorie, pk=modul_id)  
    ...
        low, high, result =aufgabenstellung(modul_id)      
Jetzt bin ich übermütig geworden und habe in meine Tabelle "Kategorie" ein Feld "function" eingefügt und dort z.B. den Wert "subtrahieren" eingetragen
und

Code: Alles auswählen

low, high, result =aufgabenstellung(modul_id) 
durch

Code: Alles auswählen

low, high, result =modul.function()
ersetzt. Das funktioniert nicht ("'str' object is not callable"). Wo ist mein Denkfehler?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du schlägst die nicht in einem Dictionary nach. Sondern rufst einen String auf.
Sirius3
User
Beiträge: 18264
Registriert: Sonntag 21. Oktober 2012, 17:20

Dafür ist das Wörterbuch `AUFGABEN` da, das den String einer Funktion zuordnet.
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

OK, also ersetzt das Dictonary nicht nur meinen Wert in einen String sondern ist explizit dafür, da eine Funktion aufzurufen?
Nun gut, das hätte mir ansonsten 37 Zeilen Code erspart.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es bildet die Werte (zahlen oder strings kannst du dir aussuchen) auf ein Funktionsobjekt ab.

eine_funktion

Ist keine String. Gib dir das mal mir print aus, zb

print(print) # man beachte die fehlenden inneren Klammern

Du kannst solche Objekte dann einfach aufrufen. Siehe zb

Code: Alles auswählen

magie = print # schon wieder keine Klammern 
magie('Ups, was passiert hier?')
Pitwheazle
User
Beiträge: 1053
Registriert: Sonntag 19. September 2021, 09:40

Nun, ja, hätte ja klappen können, dass man durch Anhängen von () aus einem string einen Funktionsaufruf machen kann.
Antworten