kunci asing
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) Memiliki parameter yang diperlukan untuk mengadopsi kelas model target.
Kolom dan tipe Sqlalchemy secara otomatis diambil dari model target.
- Kolom Sqlalchemy: Kelas untuk model target kolom kunci primer
- Tipe (untuk pydantic): jenis model target
Tentukan modelnya
Untuk menentukan suatu hubungan, tambahkan bidang kunci asing yang menunjuk ke model yang relevan.
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)
|
hubungan terbalik
Bidang kunci asing secara otomatis mencatat sisi kebalikan dari hubungan.
Secara default, ini adalah nama model anak (sumber) + s, seperti dalam cuplikan kode berikut:
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())
|
Hubungan terbalik mengekspos API untuk mengelola objek terkait dari orang tua.
Lewati hubungan terbalik
Jika Anda yakin tidak menginginkan hubungan terbalik, Anda dapat menggunakan skip\ _ reverse = Bendera asli untuk kunci asing.
Jika Anda mengatur bendera lewati\ _ mundur secara internal, bidang tersebut masih terdaftar di ujung lain hubungan, sehingga Anda dapat:
- Filter dengan bidang model yang relevan dalam model terbalik
- Pesanan\ _ oleh Bidang Model Terkait dalam Model Terbalik
Tapi Anda tidak bisa:
- Gunakan\ _ nama terkait untuk mengakses bidang terkait dari model terbalik
- Bahkan jika Anda memilih korelasi dari sisi sebaliknya model, model yang dikembalikan tidak akan diisi dalam contoh terbalik (tidak ada koneksi yang akan diblokir, sehingga Anda masih dapat menyaring dan mengurutkan hubungan).
- Hubungan tersebut tidak dihuni dalam model\ _ dump () dan model\ _ dump\ _ json ()
Ketika* dihuni dari kamus atau json (juga melalui fastapi), Anda tidak dapat melewati objek terkait yang bersarang. Tergantung pada pengaturan ekstra dalam konfigurasi pydantic, itu akan diabaikan atau kesalahan dilemparkan.
Contoh:
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 | Kelas Penulis (ormar. Model):
ormar _ config = base _ ormar _ config copy ()
Id: int = ormar. Integer (primary _ key = Benar)
nama _ pertama: str = ormar. String (max _ length = 80)
Nama belakang: str = ormar. String (max _ length = 80)
Pos Kelas (ormar. Model):
ormar _ config = base _ ormar _ config copy ()
Id: int = ormar. Integer (primary _ key = Benar)
Judul: str = ormar. String (max _ length = 200)
Author: Opsional [Author] = ormar. ForeignKey (Author, skip _ reverse = Benar)
# membuat data sampel
Author = Author (first _ name = "Test," last _ name = "Author")
Post = Post (judul = "Test Post," author = author)
Tegaskan post.author = = penulis
Tegaskan author.post # Kesalahan atribut!
# tapi masih bisa digunakan secara berurutan _ by
Penulis = (
await Author.objeks.pilih _ terkait ("posting").order _ by ("posting _ _ judul").all ()
)
Tegaskan penulis [0]. first _ name = = "Tes"
# perhatikan bahwa posting tidak diisi untuk penulis bahkan jika secara eksplisit
# termasuk dalam pilih _ terkait - catatan tidak ada posting dalam model _ dump ()
model _ dump (tidak termasuk ={"id"}) = ={"first_name": "Test", "last_name": "Author"}
# masih dapat memfilter melalui bidang model terkait
Penulis = menunggu Author.objeks.filter (posting _ _ title = "Pos Tes").all ()
Tegaskan penulis [0]. first _ name = = "Tes"
Assert len (penulis) = = 1
|
menambahkan
Menambahkan model anak dari orang tua menyebabkan model terkait ditambahkan ke orang tua yang saat ini dimuat, menetapkan model anak nilai-nilai kunci asing, dan memperbarui model.
| Departemen = menunggu Departemen (nama = "Sains").simpan ()
Kursus = Kursus (nama = "Matematika," selesai = Salah) # catatan - tidak disimpan
Menunggu department.courses (kursus)
Assert course.pk tidak ada # model anak disimpan
# relasi pada model anak diatur dan kolom FK disimpan dalam db
Kursus tegas.departemen = = departemen
# hubungan pada model induk juga diatur
Tegaskan department.courses [0] = = kursus
|
!!!Peringatan: Jika Anda ingin menambahkan model anak ke model terkait, nilai kunci utama model orang tua harus ada di database.
| Jika tidak, ormar akan meningkatkan `RelationshipInstanceError` karena tidak dapat mengatur nilai kolom Kunci ForeignKey anak
Jika model induk tidak memiliki nilai kunci primer.
Itu berarti bahwa dalam contoh di atas departemen harus disimpan sebelum Anda dapat menelepon `department.courses.add()`.
|
!!!Peringatan: Metode ini tidak bekerja dengan banyak hubungan - dalam hal ini, kedua sisi hubungan harus diselamatkan sebelum ditambahkan ke hubungan.
menghilangkan
Model yang relevan dihapus satu per satu.
Dalam hubungan terbalik, panggilan hapus () tidak menghapus submodel, tetapi menetapkan nilai ForeignKey-nya menjadi nol.
| # melanjutkan dari atas
Tunggu department.courses hapus (tentu saja)
Assert len (department.courses) = = 0
# tentu saja masih ada dan disimpan dalam penghapusan
Tegaskan course.pk tidak ada
Kursus pencuci mulut. Departemen adalah Tidak Ada
# untuk menghapus anak-anak dari db
Menunggu tentu saja.hapus ()
|
Tetapi jika Anda ingin menghapus hubungan dan menghapus anak-anak pada saat yang sama, Anda dapat mengeluarkan:
| # ini tidak hanya akan menghapus hubungan
# tetapi juga menghapus kursus terkait dari db
Tunggu department.courses hapus (tentu saja, tetap _ terbalik = Salah)
|
bening
Satu panggilan menghapus semua model terkait.
Seperti halnya penghapusan, secara default, clear () akan mengosongkan kolom ForeigKey pada model anak (semua, apakah dimuat atau tidak).
| # nulls kolom departemen pada semua kursus yang terkait dengan departemen ini
Ditunggu department.courses jelas
|
Jika Anda ingin sepenuhnya menghapus item anak dari database, set tetap\ _ terbalik = Salah
| # menghapus dari db semua kursus yang terkait dengan departemen ini
Tunggu department.courses jelas (tetap _ terbalik = Salah)
|
Agen Setelan Kueri
Hubungan terbalik memaparkan QuerysetProxy API, yang memungkinkan Anda untuk menanyakan model terkait seperti yang Anda lakukan pada pertanyaan normal.
Untuk mempelajari metode QuerySet mana yang tersedia, baca querysetproxy di bawah ini
nama terkait
Anda dapat mengesampingkan nama bidang model yang relevan dengan memberikan parameter\ _ nama terkait sebagai berikut:
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'))
|
!!!Hubungan terbalik pada akses tip mengembalikan daftar wekref.proxy untuk menghindari referensi melingkar.
!!!memperingatkan ketika Anda menyediakan beberapa hubungan ke model yang sama, nama\ _ terkait tidak lagi dapat dibuat secara otomatis untuk Anda.
Oleh karena itu, dalam hal ini, Anda harus memberikan\ _ nama terkait untuk semua bidang atau semua bidang terkait kecuali satu (satu dapat menjadi default dan dihasilkan).
tindakan referensi
Ketika objek yang dirujuk oleh ForeignKey berubah (menghapus atau memperbarui), ormar mengatur batasan SQL yang ditentukan oleh parameter ondelete dan onupdate.
Kemungkinan nilai untuk ondelete dan onupdate dapat ditemukan di ormar. Tindakan Referensi:
Catatan!!!Anda dapat mengoper nilai string langsung ke dua parameter ini, bukan ormar. Referensi, tetapi ini tidak disarankan karena akan merusak integritas.
Cascade
Setiap kali baris di tabel orang tua (referensi) dihapus (atau diperbarui), baris yang sesuai di tabel anak (referensi) dengan kolom kunci asing yang cocok juga dihapus (atau diperbarui). Ini disebut penghapusan cascading (atau pembaruan).
pembatasan
Ketika ada baris dalam tabel referensi atau subtabel yang merujuk nilai dalam tabel referensi, nilai tidak dapat diperbarui atau dihapus.
Demikian pula, selama ada referensi ke baris di tabel referensi atau tabel anak, baris tidak dapat dihapus.
Set\ _ NULL
Set ForeignKey to None; ini hanya mungkin jika nullable adalah Benar.
Setel nilai default
Setel ForeignKey ke nilai default; server\ _ default untuk ForeignKey harus disetel.
!!!Perhatikan bahwa default tidak diperbolehkan, Anda harus melakukan ini melalui server\ _ default, yang dapat Anda baca di bagian ini.
Tidak melakukan apa-apa.
Tidak ada tindakan yang diambil; tidak ada tindakan dan pembatasan yang sangat mirip. Perbedaan utama antara NO ACTION dan RESTRICT adalah, untuk NO ACTION, pemeriksaan integritas referensial dilakukan setelah upaya untuk mengubah tabel. RESTRICT memeriksa sebelum upaya untuk melaksanakan UPDATE atau DELETE statement.
Jika pemeriksaan integritas referensi gagal, kedua operasi referensi berperilaku sama: pernyataan UPDATE atau DELETE menghasilkan kesalahan.
pengaturan hubungan
Anda dapat menjalin hubungan dengan berbagai cara.
Contoh model
Yang paling jelas adalah menyampaikan contoh Model yang relevan kepada konstruktor.
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)
|
nilai kunci utama
Anda juga dapat mengatur hubungan hanya dengan menggunakan nilai kolom PK dari model yang relevan.
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)
|
kamus
Opsi selanjutnya adalah menggunakan kamus nilai kunci model yang relevan.
Anda bisa membuat kamus sendiri atau mendapatkannya dari model yang sudah ada menggunakan metode 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)
|
Tidak ada apa-apa.
Akhirnya, Anda dapat secara eksplisit mengaturnya ke Tidak Ada (perilaku default jika tidak ada nilai yang dilewatkan).
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)
|
!!!Peringatan: Dalam semua kasus non-Tidak ada, nilai kunci utama dari model yang relevan harus ada dalam database.
| Jika tidak, IntegrityError akan dinaikkan oleh perpustakaan driver database Anda.
|