Zum Inhalt

außen außen

ForeignKey(to: Model, *, name: str = None, unique: bool = False, nullable: bool = True, related_name: str = None, virtual: bool = False, onupdate: Union[ReferentialAction, str] = None, ondelete: Union[ReferentialAction, str] = None, **kwargs: Any) Verfügt über die erforderlichen Parameter, um die Zielmodellklasse zu übernehmen.

Sqlalchemy-Spalten und-Typen werden automatisch aus dem Zielmodell abgerufen.

  • Sqlalchemy-Spalte: Klassen für die Primärschlüsselspalten des Zielmodells
  • Typ (für pydantisch): Typ des Zielmodells

Definitionsmodell

Zum Definieren einer Beziehung fügen Sie ein Fremdschlüsselfeld hinzu, das auf das zugehörige Modell verweist.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from typing import Optional

import databases
import ormar
import sqlalchemy

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Department(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Department] = ormar.ForeignKey(Department)

Gegensätzliche Beziehung

Das Fremdschlüsselfeld registriert automatisch das Gegenteil einer Beziehung.

Standardmäßig ist es der Name des Untermodells (Quelle)+ s, wie in dem folgenden Codefragment gezeigt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import asyncio
from typing import Optional

import databases
import ormar
import sqlalchemy
from examples import create_drop_database

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)


class Department(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="departments")

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Department] = ormar.ForeignKey(Department)


@create_drop_database(base_config=ormar_base_config)
async def verify():
    department = await Department(name="Science").save()
    course = Course(name="Math", completed=False, department=department)
    print(department.courses[0])
    # Will produce:
    # Course(id=None,
    #        name='Math',
    #        completed=False,
    #        department=Department(id=None, name='Science'))
    await course.save()


asyncio.run(verify())

Reverse-Relationships Öffentliche API zum Verwalten verwandter Objekte vom übergeordneten Ende aus.

Sprung in die Gegenbeziehung

Wenn Sie sicher sind, dass Sie keine umgekehrte Beziehung wünschen, können Sie das Flag skip_reverse = True des Fremdschlüssels verwenden.

Wenn Sie intern das skip_reverse-Flag gesetzt haben, ist das Feld immer noch am anderen Ende der Beziehung registriert, sodass Sie:

  • Filtern nach relevanten Modellfeldern im umgekehrten Modell
  • order_by Das verwandte Modellfeld im umgekehrten Modell

Aber Sie können nicht:

  • Verwenden von related_name zum Zugreifen auf relevante Felder aus einem umgekehrten Modell
  • Selbst wenn Sie die Korrelation von der Rückseite des Modells auswählen, wird das zurückgegebene Modell nicht in die Reverse-Instanz aufgefüllt (Verbindungen werden nicht blockiert, sodass Sie die Beziehungen trotzdem filtern und sortieren können).
  • Die Beziehung wird nicht in model_dump () und model_dump_json () aufgefüllt. Wenn* aus einem Wörterbuch oder Json (auch über fastapi) gefüllt wird, können Sie kein verschachteltes verwandtes Objekt übergeben, das aufgrund zusätzlicher Einstellungen in der pydantischen Konfiguration ignoriert wird oder einen Fehler auslöst.

Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Autor (ormar. model):
    ormar_config = base_ormar_config. copy ()(= Grundeinheit von Ormar_config. copy)

    id: int = ormar. Integer (primary_key = true)(nicht bekannt)
    first _ name : str = ormar . String (max _ length = 80) (string = ormar . String (max _ length = 80)) (Übersetzung)
    last _ name : str = ormar . String (max _ length = 80) (string = ormar . String (max _ length = 80)) (max _ length = 80)


Klasse Post (ormar . model) :
    ormar _ config = base _ ormar _ config . copy () (= Grundeinheit von Ormar _ config . copy)

    id : int = ormar . Integer (primary _ key = true) (nicht bekannt)
    title : str = ormar . String (max _ length = 200)
    author : Optional [ Autor ] = ormar . ForeignKey (Author , skip _ reverse = True)

Erstellen von Sample Data
author = Autor (erster _ name = " Test " , letzter _ name = " Autor ")
post = Post (title = " Testbeitrag " , author = Autor)

Assert hinzufügenpost.authorBenutzer # OK
assert author . posts # Attributfehler !

# Aber immer noch kann in der Reihenfolge verwendet werden _ by
Die Autoren (
    Await sehenAuthor.objects.select_ related (" posts ") . order _ by (" posts _ _ title ") . all (" Einträge ")
)
assert authors [ 0 ] . first _ name = = " Test " (Testbericht)

# note , dass post nicht für den author populär ist , auch wenn ausdrücklich
# included in select _ related - note no posts in model _ dump () [ Bearbeiten | Quelltext bearbeiten ]
Model _ dump (exclude ={"id"}) = ={"first_name": "Test", "last_name": "Author"}(Hinzufügen)

# still kann durch Felder von verwandten Modellen filtern .
authors = await Author . objects . filter (posts _ _ title = " Testbeitrag ") . all ()
assert authors [ 0 ] . first _ name = = " Test " (Testbericht)
assert len (Autoren) = 1

Hinzufügen

Das Hinzufügen eines Kindermodells vom übergeordneten Ende führt dazu , dass das relevante Modell der aktuell geladenen übergeordneten Beziehung hinzugefügt , ein externer Schlüsselwert des Kindermodells gesetzt und das Modell aktualisiert wird .

1
2
3
4
5
6
7
8
9
department = await Department (name = " Wissenschaft ") . save ()
course = Kurs (name = " Math " , completed = False) # note - not saved (" Kurs " = " Math " , abgeschlossen = False ")

Kursleitung . Kurse . add (Kurse)
Assert hinzufügencourse.pkis not None # Kindermodell wurde gerettet
# relation on child model is set and FK column saved in db [ Bearbeiten | Quelltext bearbeiten ]
assert course . department = Abteilung
# Beziehung auf dem Parent Model is also Set
assert department.courses [ 0 ] = natürlich

!!!Warnung Wenn Sie ein Untermodell zum verknüpften Modell hinzufügen möchten , muss der Primärschlüsselwert des übergeordneten Modells in der Datenbank vorhanden sein .

1
2
3
4
Otherwise ormar wird `RelationshipInstanceError` raise , da es nicht möglich ist , den ForeignKey des Kindes zu setzen
Wenn das Parent Model keinen Primärschlüsselwert hat ,

Dies bedeutet zum Beispiel , dass über der Abteilung muss gespeichert werden , bevor Sie `department.courses.add()` anrufen können .

!!!Warnung Diese Methode eignet sich nicht für Mehr-zu - Mehr-Beziehungen - in diesem Fall müssen beide Seiten der Beziehung gespeichert werden , bevor sie zur Beziehung hinzugefügt werden können .

Beseitigung

1 . Das entsprechende Modell wird gestrichen .

In einer umgekehrten Beziehung löscht der Aufruf von remove () das Untermodell nicht , sondern setzt dessen ForeignKey-Wert auf Null .

1
2
3
4
5
6
7
8
9
Fortsetzung von oben nach oben
Entfernung , Entfernung (Kurs)
assert len (department.courses) = 0
Der Kurs existiert noch und wurde in entfernt
Assert hinzufügencourse.pkist nicht keiner
assert course , department ist none

Entfernen von Kindern aus DBA
Der Kurs ist abgehakt . [ … ]

Wenn Sie jedoch die Beziehung löschen und gleichzeitig die Unterelemente löschen möchten , können Sie Folgendes ausgeben :

1
2
3
Dies wird nicht nur die Beziehung klären
#Aber auch damit verbundene Kurse von DBK löschen
wait department. courses. remove (natürlich, keep_reversed = False)

Aufräumen

Ein Aufruf entfernt alle relevanten Modelle auf einmal.

Wie beim Löschen löscht auch clear () standardmäßig die ForeigKey-Spalte auf dem Untermodell (alle, unabhängig davon, ob sie geladen werden oder nicht).

1
2
* nulls department column on all courses related to this department//nulls department column on all courses related to this department/nulls department auf allen Plätzen im Zusammenhang mit dieser Abteilung
Wohnung mieten, mieten, sauber ()

Wenn Sie das untergeordnete Element vollständig aus der Datenbank entfernen möchten, legen Sie keep_reversed = False fest

1
2
Alle DB-Lieferungen sind in dieser Abteilung
await department. courses. clear (keep_reversed = False)(wait department. courses. clear (keep_reversed = False) ist eine

Frage an den Vereinsvertreter

Umgekehrte Beziehungen machen die QuerysetProxy-API verfügbar, mit der Sie relevante Modelle genauso abfragen können, wie Sie normale Abfragen ausführen würden.

Welche Methoden von QuerySet verfügbar sind, lesen Sie weiter unten mit querysetproxy.

Entsprechende Namen

Sie können den Namen des zugehörigen Modellfelds überschreiben, indem Sie den Parameter related_name wie folgt angeben:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from typing import Optional

import databases
import ormar
import sqlalchemy

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)


class Department(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Department] = ormar.ForeignKey(
        Department, related_name="my_courses"
    )


department = Department(name="Science")
course = Course(name="Math", completed=False, department=department)

print(department.my_courses[0])
# Will produce:
# Course(id=None,
#        name='Math',
#        completed=False,
#        department=Department(id=None, name='Science'))

!!!Die umgekehrte Beziehung beim Zugriff auf tip gibt die Liste wekref. proxy zurück, um wiederkehrende Verweise zu vermeiden.

!!!warnt, dass, wenn Sie mehr als eine Beziehung zum gleichen Modell angeben, sonst wird es nicht mehr möglich sein, automatisch related_name für Sie zu generieren Daher müssen Sie in diesem Fall related_name für alle Felder oder alle verwandten Felder außer einem Feld angeben (von dem eines der Standardwerte und das Ergebnis sein kann).

Referenz Aktion

Wenn ein von ForeignKey referenziertes Objekt geändert (gelöscht oder aktualisiert) wird, setzt ormar die von den Parametern ondelete und onupdate angegebenen SQL-Einschränkungen.

Mögliche Werte für ondelete und onupdate finden Sie in ormar. ReferentialAction:

!!!note Sie können Zeichenfolgenwerte direkt an diese beiden Parameter übergeben, anstatt an ormar. ReferentialAction, aber es wird nicht empfohlen, da dies die Integrität beeinträchtigen würde.

Kaskade aus Kaskaden

Jedes Mal, wenn eine Zeile in der übergeordneten (referenzierten) Tabelle gelöscht (oder aktualisiert) wird, wird die entsprechende Zeile in der untergeordneten (referenzierten) Tabelle mit der entsprechenden Fremdschlüsselspalte ebenfalls gelöscht (oder aktualisiert).

Begrenzung

Wenn es eine Zeile in der referenzierten Tabelle oder Untertabelle gibt, die auf den Wert in der referenzierten Tabelle verweist, kann der Wert nicht aktualisiert oder gelöscht werden.

Ebenso kann diese Zeile nicht gelöscht werden, solange sie in der referenzierten Tabelle oder Untertabelle einen Verweis auf eine Zeile enthält.

Einrichtung_Null

Setzen Sie ForeignKey auf None; dies ist nur möglich, wenn nullable auf True gesetzt ist.

Erstelle einen Bestätigungswert.

ForeignKey wird auf den Standardwert gesetzt; server_default muss für ForeignKey festgelegt werden.

!!!note Bitte beachten Sie, dass die Standardwerte nicht zulässig sind und Sie dies über server_default tun müssen, wie Sie in diesem Abschnitt lesen können.

Nichts tun.

keine Maßnahmen ergreifen; Der Hauptunterschied zwischen NO ACTION und RESTRICT besteht darin, dass bei NO ACTION die referenzielle Integritätsprüfung nach dem Versuch, die Tabelle zu ändern, durchgeführt wird RESTRICT wird, bevor versucht wird, eine UPDATE-oder DELETE-Anweisung auszuführen, wenn die referenzielle Integritätsprüfung fehlschlägt, verhält sich die referenzielle Integritätsprüfung gleich: Eine UPDATE-oder DELETE-Anweisung führt zu einem Fehler.

Beziehung einrichten

Sie können auf verschiedene Weise eine Verbindung aufbauen.

Modell Beispiele

Eine der offensichtlichsten ist die Übergabe verwandter Model-Instanzen an Konstruktoren.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from typing import Dict, Optional, Union

import databases
import ormar
import sqlalchemy

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Department(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Union[Department, Dict]] = ormar.ForeignKey(Department)


department = Department(name="Science")

# set up a relation with actual Model instance
course = Course(name="Math", completed=False, department=department)

# set up  relation with only related model pk value
course2 = Course(name="Math II", completed=False, department=department.pk)

# set up a relation with dictionary corresponding to related model
course3 = Course(name="Math III", completed=False, department=department.model_dump())

# explicitly set up None
course4 = Course(name="Math III", completed=False, department=None)

Der Hauptschlüssel

Sie können die Beziehung auch nur mit dem pk-Spaltenwert des jeweiligen Modells festlegen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from typing import Dict, Optional, Union

import databases
import ormar
import sqlalchemy

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Department(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Union[Department, Dict]] = ormar.ForeignKey(Department)


department = Department(name="Science")

# set up a relation with actual Model instance
course = Course(name="Math", completed=False, department=department)

# set up  relation with only related model pk value
course2 = Course(name="Math II", completed=False, department=department.pk)

# set up a relation with dictionary corresponding to related model
course3 = Course(name="Math III", completed=False, department=department.model_dump())

# explicitly set up None
course4 = Course(name="Math III", completed=False, department=None)

Das Wörterbuch

Die nächste Option ist die Verwendung von Schlüssel-Wert-Dictionaries für verwandte Modelle.

Sie können Ihr eigenes Wörterbuch erstellen oder es aus einem vorhandenen Modell mithilfe der Methode model_dump () abrufen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from typing import Dict, Optional, Union

import databases
import ormar
import sqlalchemy

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Department(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Union[Department, Dict]] = ormar.ForeignKey(Department)


department = Department(name="Science")

# set up a relation with actual Model instance
course = Course(name="Math", completed=False, department=department)

# set up  relation with only related model pk value
course2 = Course(name="Math II", completed=False, department=department.pk)

# set up a relation with dictionary corresponding to related model
course3 = Course(name="Math III", completed=False, department=department.model_dump())

# explicitly set up None
course4 = Course(name="Math III", completed=False, department=None)

Keine Nichts.

Schließlich können Sie es explizit auf None setzen (das Standardverhalten, wenn kein Wert übergeben wird).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from typing import Dict, Optional, Union

import databases
import ormar
import sqlalchemy

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Department(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    completed: bool = ormar.Boolean(default=False)
    department: Optional[Union[Department, Dict]] = ormar.ForeignKey(Department)


department = Department(name="Science")

# set up a relation with actual Model instance
course = Course(name="Math", completed=False, department=department)

# set up  relation with only related model pk value
course2 = Course(name="Math II", completed=False, department=department.pk)

# set up a relation with dictionary corresponding to related model
course3 = Course(name="Math III", completed=False, department=department.model_dump())

# explicitly set up None
course4 = Course(name="Math III", completed=False, department=None)

!!!Warnung: In allen Nicht-None-Fällen müssen die Primärschlüsselwerte des betreffenden Modells in der Datenbank vorhanden sein.

1
Ein Integritätsfehler wird durch die Treiberbibliothek Ihrer Datenbank verursacht.