Initiale Werte einer Inline-Instanz in Django-Admin

Django, Flask, Bottle, WSGI, CGI…
Antworten
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Hallo,

ich habe die folgenden Modelle:

Code: Alles auswählen

#models.py

class Termin(models.Model):
    start = models.DateTimeField()
    klasse = models.ForeignKey(
        'Klasse', on_delete=models.CASCADE, related_name="termin")
    ....
    
class Klasse(models.Model):
    ....
und wie folgt im Admin registriert:

Code: Alles auswählen

# admin.py
...
class TerminInline(admin.TabularInline):
    model = Termin
    extra = 0

class KlasseAdmin(admin.ModelAdmin):
    inlines = [
        TerminInline,
    ]

admin.site.register(Klasse, KlasseAdmin)
...
Ich würde gerne erreichen, dass für neue TerminInlines wie folgt initiale Daten gesetzt werden.
- Für den ersten Termin keine initialen Daten
- Ab dem zweiten Termin soll die Startzeit genau eine Woche späte sein (wie ich das mit der Zeitspanne hinbekomme ist mir klar, also über timedelta)

Bild
(wg. Alltagskurs Erziehung, es handelt sich um ein Projekt für eine Hundeschule, dass ich ohne Bezahlung umsetze)

Beim Eintragen der Inlines sind die Daten ja noch nicht gespeichert. Kann ich dieses Verhalten dann überhaupt realisieren? Oder muss ich zumindest den ersten Termin zusammen mit der neuen Klasse speichern?

Ich finde hier keinen Ansatzpunkt, wie ich das umsetzen kann. Vermutlich brauche ich die get_formset()-Methode aus dem TabularInline. Aber da ist mir nicht ganz klar, wie ich an die Daten komme und die initialen Werte setze.

Feedback wäre klasse.
Benutzeravatar
sparrow
User
Beiträge: 4591
Registriert: Freitag 17. April 2009, 10:28

Kannst du vollständig benutzbare model.py und admin.py posten. Dann schau ich mir das mal an.
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Code: Alles auswählen

#models.py

from django.db import models

class Termin(models.Model):
    start = models.DateTimeField()
    klasse = models.ForeignKey(
        'Klasse', on_delete=models.CASCADE, related_name="termin")
    
class Klasse(models.Model):
    klassenname = models.CharField(max_length=120)

Code: Alles auswählen

# admin.py

from django.contrib import admin
from .models import Termin, Klasse

class TerminAdmin(admin.ModelAdmin):
    pass

    
admin.site.register(Termin, TerminAdmin)


class TerminInline(admin.TabularInline):
    model = Termin
    extra = 0


class KlasseAdmin(admin.ModelAdmin):
    inlines = [
        TerminInline,
    ]
  

admin.site.register(Klasse, KlasseAdmin)


Danke für deine Mühe.
Meine Modelle sind natürlich umfangreicher, aber das spielt nicht in die Fragestellung hinein. Bei Bedarf gebe ich dir gerne Zugang zum vollständigen Code und zum Testserver Admin-Bereich.
Benutzeravatar
sparrow
User
Beiträge: 4591
Registriert: Freitag 17. April 2009, 10:28

Nur zum Verständnis: Du möchtest, dass - wenn du einen neuen Termin einträgst - automatisch das DateTimeField für start gefüllt wird, und zwar abhängig zum vorherigen Termin?
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Ja, genau. genau genommen zum vorherigen Termin zur gleichen Klasse-Instanz. Beim Eintragen (vor dem Speichern) ist das wahrscheinlich nicht möglich. Dann aber zumindest so, dass ich die Klasse mit einem Termin anlege , dann speichere und wenn ich jetzt wieder die Klasse aufrufe und einen neuen Termin eintrage der Starttermin abhängig vom Starttermin des vorherigen Termin vorgeschlagen wird.

Eigentlich geht es insbesondere um die Uhrzeit. Nervt halt, wenn man für jede Klasse bei jedem Termin immer wieder die gleiche Uhrzeit einträgt (jede Klasse hat in der Regel sechs Termine). Leider ist es aber eben nicht in 100% der Fälle die gleiche Uhrzeit. Sonst könnte man ja ein TimeField in der Klasse setzen und dann das start-DateTimeField bei Bedarf bilden.

Ich könnte natürlich auch für die Pflege der Klassen einen Pflegeview für admins programmieren und das ganze über Javascript lösen. Aber da alles andere Adminbereich von Django gepflegt wird, wäre mir eine Lösung dort lieber.
Benutzeravatar
sparrow
User
Beiträge: 4591
Registriert: Freitag 17. April 2009, 10:28

Und was machst du, wenn der Benutzer nicht nur 1 sondern 2 oder 6 Termine hinzufügt? Die sind dann ja nur im Frontend bekannt, bis sie gespeichert sind.
Ich würde das tatsächlich in JavaScript lösen, allerdings im Admin-Bereich.
Immer wenn ein neuer Termin hinzugefügt wird, schauen ob es schon einen auf der Seite gibt, ob der Datum und Zeit trägt und das dann in dem neuen Datensatz eintragen. Ich denke, das wäre die beste Möglichkeit.

Wenn ich heute Abend früh daheim sein sollte, schaue ich mal, wie schwer das ist. Aber JavaScript ist nicht so meins.
Zuletzt geändert von sparrow am Montag 28. Oktober 2019, 15:12, insgesamt 1-mal geändert.
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Danke für den Link zur Admin-Customization. Man lernt nie aus, kannte ich noch überhaupt nicht. Aber das könnte klappen. Setze mich morgen mal ran und berichte.
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

@sparrow: vielen Dank für den Hinweis. Ist relativ simpel, wenn man weiß wie es geht.

Lösung:

Code: Alles auswählen

# change_form.html in tempates/admin/training (app_name)

{% extends 'admin/change_form.html' %}
{% load static %}

{% block admin_change_form_document_ready %}
{{ block.super }}
<script type="text/javascript" src="{% static 'app/formset_handlers.js' %}"></script>
{% endblock %}

Code: Alles auswählen

#formset_handlers.js in static/app

(function ($) {
    $(document).on('formset:added', function (event, $row, formsetName) {
        if (formsetName == 'termin') {
            let id = $row[0].id.substr($row[0].id.length - 1);
            if (id > 0) {
                let source_id = '#id_termin-' + (id - 1) + '-start_1'
                let destination_id = '#id_termin-' + id + '-start_1'
                let source = $(source_id)[0].value
                let destination = $(destination_id)
                destination.val(source)
            }
        }
    });
})(django.jQuery);
bin auch kein JS und JQuery crack, da gibt es bestimmt noch Optimierungen :)
Antworten