Django Model Inheritance

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
Judge
User
Beiträge: 129
Registriert: Mittwoch 13. Juni 2012, 22:27
Wohnort: Ratingen
Kontaktdaten:

Hallo zusammen,

ich habe versucht mich durch die Django-Docs selbst hindurch zu fuchsen, stoße dabei aber leider an meine Grenzen und brauche das etwas leichter verdaulich ...

Ich schreibe gerade eine Django-App, in der User eine URL zu einem Album oder einzelnem Track in Google Music eingeben können und die App extrahiert dann die Metadaten, die Google hierzu gespeichert hat. In einem einfachen Django Web-Form gibt es daher nur ein einziges Feld für die URL.
Dieser Request wird in der Datenbank zur späteren Verarbeitung mit diesem Model gespeichert:

Code: Alles auswählen

class DownloadRequest(models.Model):
    link = models.CharField(max_length=500, blank=False, null=True)
    description = models.CharField(max_length=500, blank=True)
    dl_requestors = models.ForeignKey(
        settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL
    )
    job_created = models.DateTimeField(blank=True, null=True, default=timezone.now)
    has_error = models.BooleanField(default=False)
Dieses funktioniert soweit auch schonmal ganz gut.
Jetzt können sich hinter einer URL zwei verschiedene für mich relevante Dinge verbergen:
  1. Eine Playlist / Album
  2. Ein einzelner Song
Also habe ich zwei weitere Models definiert, welche auf dieser Basisklasse basieren:

Code: Alles auswählen

class Album(DownloadRequest):
    artist = models.CharField(max_length=500, blank=True)
    title = models.CharField(max_length=500, blank=True)
    resolved = models.BooleanField(default=False)
    tracks_resolved = models.BooleanField(default=False)

class Track(Album):
    metadata_resolved = models.BooleanField(default=False)
Grundsätzlich bildet das genau das ab, was ich damit machen möchte: Handelt es sich um ein Album soll ein Datenbankobjekt "Album" erzeugt werden; programmatisch muss ich dann noch alle Tracks dieses Albums heraussuchen, eigene "Track" Datenbankeinträge hierfür anlegen die in Relation zu dem jeweiligem Album stehen, usw.; das ist hier aber garnicht das Problem:

Mein PLAN hier ist, das ich von den User-Eingaben (Nur URL) in einem Django-Form ein DownloadRequest - Objekt erzeuge (und in der DB speichere), dann mit einer Funktion erkenne ob sich hinter dem eingegebenem Link ein Album oder ein Song verbirgt, und dann das DownloadRequest - Objekt zum einen oder anderen "upgrade". Also zum Beispiel so:

Code: Alles auswählen

download_form = DownloadForm(data=request.POST)
dl = download_form.save()
if dl.identify_url_type() == "playlist":
    _ = Album.objects.create(
                            link=dl.link,
                            description=dl.description,
                            dl_requestors=dl.dl_requestors,
                        )
else:
    _ = Track.objects.create(
                            link=dl.link,
                            description=dl.description,
                            dl_requestors=dl.dl_requestors,
                        )
_.save()
Leider habe ich keine bessere Möglichkeit gefunden in der man nur etwas wie Album.objects.create(DownloadRequest()) machen kann; daher ist der Code hier leider nicht wirklich optimal, aber ich finde: Nachvollziehbar, was ich da beabsichtige, ist es.
Meine Erwartung wäre jetzt, das im Falle von Album.objects.create() ein neues Objekt in der Datenbank-Tabelle für das Model "Album" angelegt wird.
Stattdessen wird jedoch sowohl ein Objekt in der Tabelle "Albums" sowie auch eines in der Tabelle "DownloadRequest" erzeugt, welche zueinander in Relation stehen; dieses sieht man sehr gut beim löschen des neu erzeugten DownloadRequest-Objektes, da diese CASCADED gelöscht werden:

Bild

Dabei brauche ich das DownloadRequest-Objekt ja garnicht mehr; im Gegenteil: Wenn ich statt ein neues Album-Objekt anzulegen stattdessen das bestehende DownloadRequest-Objekt in ein Album-Objekt umwandeln könnte, würde ich stattdessen das tun. Was ich garnicht brauche ist ein weiteres DownloadRequest-Objekt, zusätzlich zu dem ursprünglichen DownloadRequest-Objekt.

Also, ich hoffe was ich beabsichtige und was stattdessen passiert kommt verständlich rüber; ich würde gerne ein auf einer Basisklasse basierendes Model erzeugen ohne das dabei ein Element der Basisklasse zusätzlich zur Child-Klasse erzeugt wird oder dieses sogar "umwandeln", wenn das möglich ist.
Ich hoffe jemand kann mir hier erklären was ich falsch mache (und auch was die Django-Sichtweise an der Stelle ist, damit ich das einmal grundsätzlich verstehe).

Vielen Dank für Eure Antworten!
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Wieso bindest du denn Sachen an den Namen "_"? An den Unterstrich wird nur etwas gebunden das man nicht mehr verwendet. Du tust dmit aber eine ganze Menge.

Und durch dein Vererben stellst du eine Relation her. Diese Art der Relation ist aber nicht korrekt. Man muss ein "DownloadRequest" nicht "upgraden".
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Judge: Vererbung ist eine „ist-ein(e)“-Beziehung. Ein Track ist aber ganz sicher kein Album.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten