buitenlandse sleutel
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) Heeft de parameters die nodig zijn om de doelmodelklasse over te nemen.
Sqlalchemy-kolommen en -typen worden automatisch opgehaald uit het doelmodel.
- Sqlalchemiekolom: Klasse voor primaire sleutelkolom van het doelmodel
- Type (voor pydantic): het type doelmodel
Definieer het model
Om een relatie te definiëren, voegt u een buitenlands sleutelveld toe dat naar het relevante model verwijst.
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)
|
omgekeerde relatie
Het veld vreemde sleutel registreert automatisch de keerzijde van de relatie.
Standaard is dit de kind (bron) modelnaam + s, zoals in het volgende codefragment:
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())
|
Omgekeerde relaties leggen API 's bloot om gerelateerde objecten van de ouder te beheren.
Sla de omgekeerde relatie over
Als u zeker weet dat u geen omgekeerde relatie wilt, kunt u de vlag skip\ _ reverse = True gebruiken voor de buitenlandse sleutel.
Als u de skip\ _ reverse vlag intern instelt, is het veld nog steeds geregistreerd aan de andere kant van de relatie, dus u kunt:
- Filteren op relevante modelvelden in het omgekeerde model
- Bestellen\ _ door gerelateerde modelvelden in omgekeerd model
Maar je kunt niet:
- Gebruik gerelateerde\ _ naam om toegang te krijgen tot gerelateerde velden vanuit het omgekeerde model
- Zelfs als u de correlatie aan de achterkant van het model selecteert, wordt het geretourneerde model niet in de omgekeerde instantie ingevuld (er worden geen verbindingen geblokkeerd, dus u kunt de relatie nog steeds filteren en sorteren).
- De relatie wordt niet ingevuld in model\ _ dump () en model\ _ dump\ _ json ()
Wanneer* wordt ingevuld vanuit een woordenboek of json (ook via fastapi), kun je geneste gerelateerde objecten niet doorgeven. Afhankelijk van de extra instellingen in de pydantische configuratie wordt deze genegeerd of wordt er een fout opgeworpen.
Voorbeeld:
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 | Klasse Auteur (ormar. Model):
ormar _ config = basis _ ormar _ config kopie ()
Id: int = ormar. Geheel getal (primaire _ sleutel = waar)
voornaam: str = ormar. String (max _ length = 80)
achternaam: str = ormar. String (max _ length = 80)
Klasse Post (ormar. Model):
ormar _ config = basis _ ormar _ config kopie ()
Id: int = ormar. Geheel getal (primaire _ sleutel = waar)
Titel: str = ormar. String (max _ length = 200)
Auteur: Optioneel [Auteur] = ormar. ForeignKey (Auteur, skip _ reverse = Waar)
# voorbeeldgegevens aanmaken
Auteur = Auteur (voornaam = "Test", achternaam = "Auteur")
Post = Post (title = "Test Post", auteur = auteur)
Beweren post.author = = auteur # ok
Bevestig aute.posts # Kenmerkfout!
# maar kan nog steeds gebruiken in volgorde _ by
Auteurs = (
await Auteur.objects.select _ gerelateerd ("berichten") .order _ door ("berichten _ _ titel") .all ()
)
Bevestigde auteurs [0]. voornaam = = "Test"
# Merk op dat berichten niet worden ingevuld voor auteurs, zelfs als ze expliciet zijn
# opgenomen in select _ gerelateerd - let op geen berichten in model _ dump ()
model _ dump (uitsluiten ={"id"}) = ={"first_name": "Test", "last_name": "Author"}
# kan nog steeds filteren door velden van gerelateerde modellen
Auteurs = wachten Auteur.objects.filter (berichten _ _ title = "Test Post") .all ()
Bevestigde auteurs [0]. voornaam = = "Test"
Assert len (auteurs) = = 1
|
toevoegen
Door een kindmodel van de ouder toe te voegen, wordt het gerelateerde model toegevoegd aan de momenteel geladen ouder, worden de buitenlandse sleutelwaarden van het kindmodel ingesteld en wordt het model bijgewerkt.
| Afdeling = afwachten Afdeling (name = "Science") .save ()
Cursus = Cursus (naam = "Wiskunde", voltooid = Onwaar) # noot - niet opgeslagen
wachten department.courses (cursus)
Beweren course.pk is niet Geen # kindermodel werd gered
# relatie op kindmodel is ingesteld en FK-kolom opgeslagen in db
Bevestig cursus.afdeling = = afdeling
# relatie op bovenliggend model is ook ingesteld
department.courses [0] = = cursus
|
!!!Waarschuwing: als u een onderliggende model aan een gerelateerd model wilt toevoegen, moet de primaire sleutelwaarde van het bovenliggende model in de database voorkomen.
| Anders zal ormar `RelationshipInstanceError` verhogen omdat het de ForeignKey-kolomwaarde van het kind niet kan instellen
Als het bovenliggende model geen primaire sleutelwaarde heeft.
Dat betekent dat in voorbeeld hierboven de afdeling moet worden opgeslagen voordat u `department.courses.add()` kunt bellen.
|
!!!Waarschuwing: deze methode werkt niet met veel-op-veel relaties - in dit geval moeten beide kanten van de relatie worden opgeslagen voordat ze aan de relatie worden toegevoegd.
elimineren
De desbetreffende modellen worden één voor één geschrapt.
In een omgekeerde relatie wordt door het aanroepen van delete () het submodel niet verwijderd, maar wordt de ForeignKey-waarde op null gezet.
| # doorgaan van boven
Wacht department.courses verwijderen (cursus)
Stel len (department.courses) = = 0
# cursus bestaat nog en was opgeslagen in verwijderen
Beweren course.pk is geen Geen
Assert cursus. De afdeling is Geen
# om kinderen uit db te verwijderen
In afwachting van cursus.delete ()
|
Maar als u de relatie wilt wissen en tegelijkertijd de kinderen wilt verwijderen, kunt u het volgende uitgeven:
| # dit zal niet alleen de relatie duidelijk maken
# maar verwijder ook gerelateerde cursussen van db
Wacht department.courses verwijderen (natuurlijk, keep _ reversed = False)
|
duidelijk
Een enkele oproep verwijdert alle gerelateerde modellen.
Net als bij verwijdering, zal clear () standaard de ForeigKey-kolommen op het onderliggende model legen (allemaal, of ze nu zijn geladen of niet).
| # nulls afdelingszuil over alle opleidingen met betrekking tot deze afdeling
Wacht department.courses duidelijk ()
|
Als u een onderliggende item volledig uit de database wilt verwijderen, stelt u keep\ _ reversed = False in
| # schrapt uit db alle opleidingen die betrekking hebben op deze afdeling
Wacht department.courses duidelijk (keep _ reversed = False)
|
Query instellen Agent
De omgekeerde relatie legt de QuerysetProxy API bloot, waarmee u gerelateerde modellen kunt opvragen, net als bij een normale zoekopdracht.
Lees de onderstaande querysetproxy om te zien welke methoden van QuerySet beschikbaar zijn
verwante naam
U kunt de relevante modelveldnamen overschrijven door de gerelateerde\ _ name-parameter als volgt op te geven:
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'))
|
!!!De omgekeerde relatie bij tiptoegang retourneert de wekref.proxy-lijst om circulaire verwijzingen te vermijden.
!!!waarschuwt wanneer u meerdere relaties aan hetzelfde model levert, anders kan gerelateerde\ _ naam niet langer automatisch voor u worden gegenereerd.
Daarom moet u in dit geval een gerelateerde\ _ naam opgeven voor alle velden of alle gerelateerde velden behalve één (één kan de standaard zijn en worden gegenereerd).
referentie actie
Wanneer een object waarnaar wordt verwezen door ForeignKey verandert (wordt verwijderd of bijgewerkt), stelt ormar de SQL-beperkingen in die zijn gespecificeerd door de parameters ondelete en onupdate.
Mogelijke waarden voor ondelete en onupdate zijn te vinden in ormar. ReferentiëleActie:
!!!Opmerking U kunt tekenreekswaarden rechtstreeks aan deze twee parameters doorgeven in plaats van ormar. ReferentialAction, maar dit wordt niet aanbevolen omdat het de integriteit zou breken.
Cascade
Telkens wanneer een rij in de bovenliggende tabel (waarnaar wordt verwezen) wordt verwijderd (of bijgewerkt), wordt de overeenkomstige rij in de onderliggende tabel (waarnaar wordt verwezen) met overeenkomende kolommen met vreemde sleutels ook verwijderd (of bijgewerkt). Dit wordt een trapsgewijze verwijdering (of update) genoemd.
beperking
Als er een rij in de tabel of subtabel waarnaar wordt verwezen, verwijst naar een waarde in de tabel waarnaar wordt verwezen, kan de waarde niet worden bijgewerkt of verwijderd.
Evenzo kan de rij niet worden verwijderd zolang er een verwijzing is naar een rij in de tabel of onderliggende tabel waarnaar wordt verwezen.
\ _ NULL instellen
Zet ForeignKey op None; dit is alleen mogelijk als nullable Waar is.
Standaardwaarde instellen
Stel ForeignKey in op de standaardwaarde; server\ _ default voor ForeignKey moet worden ingesteld.
!!!Merk op dat de standaard niet is toegestaan, u moet dit doen via server\ _ default, waarover u in deze sectie kunt lezen.
Niets doen.
Geen actie ondernomen; geen actie en beperking lijken erg op elkaar. Het belangrijkste verschil tussen NO ACTION en RESTRICT is dat, voor NO ACTION, de referentiële integriteitscontrole wordt uitgevoerd na een poging om de tabel te wijzigen. RESTRICT controleert voordat een poging wordt gedaan om een UPDATE of DELETE-verklaring uit te voeren.
Als de referentiële integriteitscontrole mislukt, gedragen beide referentiebewerkingen zich hetzelfde: een UPDATE- of DELETE-instructie resulteert in een fout.
relatie instellingen
U kunt op verschillende manieren relaties opbouwen.
Model exemplaar
De meest voor de hand liggende is om de relevante modelinstantie door te geven aan de constructeur.
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)
|
primaire sleutelwaarde
U kunt ook relaties instellen met alleen de PK-kolomwaarden van het relevante model.
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)
|
woordenboek
De volgende optie is om het sleutelwaardewoordenboek van het relevante model te gebruiken.
U kunt het woordenboek zelf bouwen of uit een bestaand model halen met de methode model\ _ dump ().
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)
|
Niks hoor.
Ten slotte kunt u het expliciet instellen op Geen (het standaardgedrag als er geen waarde wordt doorgegeven).
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)
|
!!!Waarschuwing: in alle niet-geengevallen moet de primaire sleutelwaarde van het relevante model in de database aanwezig zijn.
| Anders wordt er een IntegrityError gegenereerd door uw database driver library.
|