Zwei unmanaged models miteinander "joinen"?

Django, Flask, Bottle, WSGI, CGI…
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Hallo zusammen,

ich bin gerade dabei mein erstes Django Projekt aufzusetzen. Ich kann leider nicht alle Daten in Django selbst generieren lassen, sondern benötige auch bereits bestehende Daten aus unserem ERP System. Deshalb habe ich über inspectdb zwei Views als Model erzeugen lassen. Meine models.py sieht wie folgt aus:

Code: Alles auswählen

from django.db import models

 

class PentaProjectMasterData(models.Model):

    project = models.CharField(max_length=10, blank=False, null=False)

    project_name = models.CharField(max_length=8000, blank=True, null=True)

    cost_bearer = models.CharField(max_length=6, blank=False, null=False, primary_key=True)

 

    class Meta:

        managed = False  # Created from a view. Don't remove.

        db_table = 'penta_project_master_data'

 

class PentaSystem(models.Model):

    system = models.CharField(max_length=4, blank=False, null=False, primary_key=True)

    system_name = models.CharField(max_length=30, blank=True, null=True)

    cost_bearer = models.CharField(max_length=6, blank=False, null=False)



    class Meta:

        managed = False  # Created from a view. Don't remove.

        db_table = 'penta_system'
Das Feld cost_bearer aus dem PentaProjectMasterData soll der Fremdschlüssel im PentaSystem Model sein. Wie mache ich das, bzw. ist das überhaupt möglich?

Viele Grüße
gospat
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

Das sollte einfach ein ForeignKey sein.
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Danke, das stimmt. Ich habe lange gebraucht um zu verstehen wie genau ich den FK setzen muss (da automatisch von Django z.B. "_id" gesetzt wird etc.).

Jetzt habe ich ein anderes Problem. Im Admin Panel versuche ich eine neue ResponsiblePerson anzulegen. Aber bei den Feldern Cost bearer und System bekomme ich im Dropdown a) viel zu viele Werte angezeigt und b) sind diese irgendwie verkettet.

So sieht meine models.py aus:

Code: Alles auswählen

from django.db import models

 

class ProjectMasterData(models.Model):

    project = models.CharField(max_length=10, blank=True, null=True)

    project_name = models.CharField(max_length=8000, blank=True, null=True)

    cost_bearer_id = models.CharField(max_length=6, blank=False, null=False)

    system_id = models.CharField(max_length=4, blank=False, null=False)

    system_name = models.CharField(max_length=30, blank=True, null=True)

    key_id = models.CharField(max_length=10, primary_key=True)

 

    class Meta:

        managed = False  # Created from a view. Don't remove.

        db_table = 'project_master_data'

 

    def __str__(self):

        return f"{self.cost_bearer_id} | {self.system_id}"

   

 

class ResponsiblePerson(models.Model):

    name = models.CharField(max_length=100, blank=False, null=False)

    department = models.CharField(max_length=100, blank=False, null=False)

   

    cost_bearer = models.ForeignKey(ProjectMasterData, on_delete=models.CASCADE, related_name='cost_bearer', db_constraint=False)

    system = models.ForeignKey(ProjectMasterData, on_delete=models.CASCADE, related_name='system', db_constraint=False)

 

    def __str__(self):

        return f"{self.department} | {self.name} | {self.cost_bearer} | {self.system}"
Wenn ich versuche einen neuen Eintrag im Admin Panel zu erzeugen, sieht es so aus, dass sowohl beim Dropdown für Cost bearer als auch für System z.B. folgendes steht: 313759 | 0310. Der Wert für Cost bearer ist aber nur "313759" und "0310" ist eigentlich der Wert für system. Was mache ich falsch bzw. wie bekomme ich das geändert?
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

Ich verstehe leider die Relation nicht. Und du scheinst ein Problem mit dem Verständnis von ForeignKeys zu haben.

Rechnungen sind immer ein gutes Beispiel.

Es gibt eine Tabelle Rechnung.
Und es gibt eine Tabelle RechnungPositionen.
Rechnung hat irgend eine Spalte, die eine ID enthält. RechnungPosition hat eine Spalte mit einem Fremdschlüssel auf auf ID in Rechnung. Denn Rechnung 1 : n RechnungPosition.

Und wie ergibt so eine Relation aus deinen Daten?
Benutzeravatar
__blackjack__
User
Beiträge: 13997
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@gospat83: Da steht halt das was die `ProjectMasterData.__str__()`-Methode von dem Objekt liefert. Wenn da was anderes stehen soll, muss der Code dort anders aussehen.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Ich verstehe leider nicht ganz wie ich das Ganze in Django umsetzen muss. Mal angenommen ich habe folgendes DB-Modell.

Tabelle Projekt
-------------------------
Projektnummer
Projektbezeichnung

Tabelle Baugruppe
------------------------------
Baugruppennummer
Baugruppenbezeichnung
FK Projektnummer aus Tabelle Projekt

Tabelle Verantwortlicher
--------------------------------------
Name
Abteilung
FK Baugruppennummer aus Tabelle Baugruppe
FK Projektnummer aus der Tabelle Projekt

Eine Baugruppe bezieht sich immer auf eine Projektnummer. Der Verantwortliche bezieht sich immer auf die Kombination aus Baugruppennummer und Projektnummer.

Ich hoffe es ist klar was ich erreichen möchte. Wie müsste dafür meine models.py aussehen? Ich verstehe noch nicht so gant was Django da automatisch alles im Hintergrund macht, z.B. mit dem ergänzen der "_id" beimForeign Key. Vermutlich scheitert das Ganze nur an Kleinigkeiten.
Benutzeravatar
__blackjack__
User
Beiträge: 13997
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@gospat83: Das sieht doppelt verbunden aus. Wenn man vom Verantwortlichen zum Projekt kommt, steht ja im Grunde auch die Baugruppe fest. Oder kann der Verantwortliche eine andere Baugruppe haben als das Projekt?
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Ich versuche es mal anhand eines Beispiels.

Baugruppe 0100 Projekt A Verantwortlicher Klaus
Baugruppe 0100 Projekt B Verantwortlicher Michael

Die Baugruppe kann es also von der Bezeichnung her in mehreren Projekten geben, aber sie hat dabei immer die selbe Baugruppennummer. Die Baugruppenbezeichnung kann sich jedoch unterscheiden.

Der Verantwortliche ist also nicht automatisch komplett für z.B. alle 0100 Baugruppen verantwortlich, sondern evtl. nur für bestimmte Projekte.

Erklärt es das?
Benutzeravatar
__blackjack__
User
Beiträge: 13997
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@gospat83: Wenn eine Baugruppe in mehr als einem Projekt verwendet werden kann, dann kann der Fremdschlüssel nicht in der Baugruppe liegen. Da kann man pro Baugruppe ja nur *einen* Wert für ein Projekt hinterlegen.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

@gospat83: Deine Erklärung passt nicht zu dem, was du da in der Datenbank abbilden möchtest. Kann ein Projekt mehr als eine Baugruppe haben?
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Ja, ein Projekt hat auf jeden Fall mehr als eine Baugruppe.
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Ich versuche mal die gewünschten Beziehungen zu skizzieren anhand von Beispielinhalten.

Tabelle Projekt
---------------
Projektnummer
1
2
3

Tabelle Baugruppe
-----------------
Baugruppennummer Baugruppenbezeichnung Projekt
0100 bez_a 1
0100 bez_b 2
0400 test 3

Tabelle Verantwortlicher
------------------------
Name Abteilung Baugruppennummer Projekt
Willy IT 0100 1
Peter Einkauf 0100 2
Klasu Controlling 0400 3
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

Dann hat Projekt eine n:m Beziehung zu den Baugruppen.
Deine Tabellen müssten also so aussehen, wenn du die nicht mit dem Django verwalten lassen möchtest.
== sind die Tabellen. Darunter die Felder. Fremdschlüssel mit dem Relation.zielfeld.

Code: Alles auswählen

== Abteilung
id
name

== MITARBEITER
id
name
abteilung (Fremschlüssel Abteilung.id)

== BAUGRUPPE
id
bezeichung

==  PROJEKT
id
bezeichnung

== BAUGRUPPE_ZU_PROJEKT
id
baugruppe (Fremschlüssel Baugruppe.id)
projekt (Fremschlüssel Projekt.id)
verantwortlicher (Fremdschlüssel Mitarbeiter.id)
baugruppenbezeichnung_im_projekt
Das müsste die entsprechend Normalisierung sein.
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Super, vielen Dank für deine Mühe.
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

@gospat83: Es lohnt auch noch einmal der Einstieg in die Dokumentation. Man kann eine Datenbank, die bereits existiert, problemlos mit Django verwenden. Es wird gar nichts daran verändert, wenn man die entsprechenden Optionen setzt. Weder werden Spalten angelegt noch müssen Spalten bestimmte Namen haben. Auch Spalten mit Fremschlüsseln _müssen_ nicht auf _id enden. Das tun sie, wenn Django sie selbst anlegt - man kann den Namen der Spalte aber auch angeben.
Wichtig ist, dass man auch beachtet, dass man trotzdem die Spalte mit dem Primärschlüssel entsprechend gleich mit der Datenbank angibt. Wenn man keine solche Spalte deklariert, wird sie automatisch in der Datenbank angelegt.
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

@sparrow: Ich muss hier nochal nachhaken, anscheinend bin ich zu blöd...

Ich habe jetzt ein unmanaged model aus einer SQL Server DB. Die DB-Tabelle heißt Projekt. In dieser Tabelle sind zwei Felder:

1. PSP_IDENT
2. Kostentraeger

Der PSP_IDENT ist der PK der Tabelle.

Nun habe ich eine zweite Tabelle direkt in Django angelegt, sprich es handelt sich um ein managed model. Diese Tabelle heißt z.B. Verantwortlicher. Diese Tabelle soll jetzt den PSP_IDENT aus der Projekt Tabelle als FK nutzen. Wie genau - und zwar ganz genau - muss mein Model dafür aussehen? Django macht aus PSP_IDENT ja immer automatisch PSP_IDENT_ID und so heißt mein DB-Feld nunmal nicht. Wie bekomme ich es hin, dass das Feld einfach seinen ursprünglichen Namen behält und ich es nutzen kann. Ich würde normalerweise ja einfach das in der Verantwortlicher Tabelle schreiben:

psp_ident = models.ForeignKey(Projekt, on_delete.models.CASCADE)

Es wäre toll, wenn mir mal jemand das genaue Model für meine Tabelle erstellen könnte, ich drehe mich hier irgendwie im Kreis.

Muss der vordere Part eigentlich immer genau dem Namen aus der anderen Tabelle entsprechen?

Viele Grüße
gospat
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

Aber wenn Django die Tabelle managen soll, dann ist es doch ok, wenn das Feld psp_ident_id heißt. Weil du dein Feld so benannt hast.
Richtiger (weil zu lesen) wäre:

Code: Alles auswählen

projekt = models.ForeignKey(Projekt, on_delete.models.CASCADE)
Dann wird ein Feld "projekt_id" in der "Verantwortlicher" angelegt. Und das ist ja auch korrekt.
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Sorry, aber ich blicke da nicht durch. Die Projekt Tabelle hat doch den PSP_Ident als PK. Den möchte ich doch auch nutzen. Eine Projekt_ID gibt es doch gar nicht oder legt Django auch bei unmanaged Models selber Spalten an?
Benutzeravatar
sparrow
User
Beiträge: 4525
Registriert: Freitag 17. April 2009, 10:28

_Du_ hast doch geschrieben, dass Django ein _id anhängt. Das tut es aber nur, wenn es ein Fremschlüsselfeld ist. Und ein vernünftiger Name für das Feld in "Verantwortlicher" ist nun mal nicht psp_ident sondern projekt. Weil mit psp_ident kein Mensch etwas anfangen kann.
Und wenn du "projekt" in "Verantwortlicher" wie von mir gezeigt als Fremschlüssel anlegst, dann heißt das Feld im Model projekt und in der Datenbank wird das Feld "projekt_id" angelegt. Das ist sinnvoll. Erklärt wird das wie immer in der Dokumentation. Das möchte man eigentlich auch nicht ändern, weil das auch auf Database-Level sehr angenehm zu lesen ist. Denn auch dort vergibt man vernünftige Namen.

Und wenn der Primary-Key in dem unmanaged Model für "Projekt" korrekt gesetzt ist (was er sein sollte, denn dein Model sollte ja der Realität der Datenbank entsprechen), dann ist es völlig egal, wie dort das Feld in der Datenbank heißt. Anhand der Definition im Model weiß Django, welches Feld verwendet werden muss (nämlich eben der PK).

Dein nicht so schön benanntes Feld PSP_IDENT ist der PK von Projekt. Der hat gar nichts mit dem Feldnamen des Fremdschlüssels in Verantwortlicher zu tun. Bis auf, dass es das Ziel des Fremdschlüssels ist. Und das ist es automatisch, wenn es korrekt als PrimaryKey im Model von "Projekt" definiert ist.
gospat83
User
Beiträge: 40
Registriert: Dienstag 21. September 2021, 14:25

Ok, jetzt ist der Groschen gefallen denke ich. Danke für deine Geduld, aber wenn man da einen Knoten im Kopf hat, ist es manchmal schwierig. Ich dachte immer, dass die Namen von PK und FK übereinstimmen müssen.

Jetzt habe ich nur noch eine weitere Frage zu dem Thema, auch wenn sie für dich wahrscheinlich glasklar ist. Wenn ich jetzt wiederum den PK der Verantwortlicher Tabelle (managed) in einer weiteren unmanaged Tabelle als FK nutzen möchte, wie muss diese unmanaged Tabelle dann aussehen? Der PK lautet ja dann verantwortlicher_id. Das heißt für mich, dass ich auch ein entsprechendes Feld mit dem Namen in meiner DB-Tabelle für das unmanaged model anlegen muss, richtig?
Antworten