Jawaban:
Berhati-hatilah untuk menyadari bahwa ada beberapa perbedaan antara OneToOneField(SomeModel)
dan ForeignKey(SomeModel, unique=True)
. Sebagaimana dinyatakan dalam The Definitive Guide to Django :
OneToOneField
Hubungan satu-ke-satu. Secara konseptual, ini mirip dengan
ForeignKey
denganunique=True
, tetapi sisi "terbalik" dari relasi akan langsung mengembalikan satu objek.
Berbeda dengan OneToOneField
relasi "mundur", relasi ForeignKey
"terbalik" mengembalikan a QuerySet
.
Misalnya, jika kita memiliki dua model berikut (kode model lengkap di bawah):
Car
menggunakan model OneToOneField(Engine)
Car2
menggunakan model ForeignKey(Engine2, unique=True)
Dari dalam python manage.py shell
jalankan yang berikut:
OneToOneField
Contoh>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>
ForeignKey
dengan unique=True
Contoh>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]
from django.db import models
class Engine(models.Model):
name = models.CharField(max_length=25)
def __unicode__(self):
return self.name
class Car(models.Model):
name = models.CharField(max_length=25)
engine = models.OneToOneField(Engine)
def __unicode__(self):
return self.name
class Engine2(models.Model):
name = models.CharField(max_length=25)
def __unicode__(self):
return self.name
class Car2(models.Model):
name = models.CharField(max_length=25)
engine = models.ForeignKey(Engine2, unique=True, on_delete=models.CASCADE)
def __unicode__(self):
return self.name
e.car
juga berfungsi?
ForeignKey
dengan unique=True
bukan OneToOneField
? Saya melihat dalam pertanyaan-pertanyaan lain bahwa Django bahkan memperingatkan bahwa OneToOneField
kepentingan yang biasanya terbaik adalah kepentingan seseorang. Kebalikannya QuerySet
tidak akan pernah memiliki lebih dari satu elemen, kan?
ForeignKey adalah untuk satu-ke-banyak, jadi objek Mobil mungkin memiliki banyak Roda, setiap Roda memiliki ForeignKey untuk Mobil miliknya. OneToOneField akan seperti Engine, di mana objek Mobil dapat memiliki satu dan hanya satu.
Cara terbaik dan paling efektif untuk mempelajari hal-hal baru adalah dengan melihat dan mempelajari contoh-contoh praktis dunia nyata. Misalkan sesaat Anda ingin membangun blog di Django di mana wartawan dapat menulis dan menerbitkan artikel berita. Pemilik surat kabar online ingin mengizinkan masing-masing reporternya menerbitkan sebanyak mungkin artikel yang mereka inginkan, tetapi tidak ingin reporter yang berbeda mengerjakan artikel yang sama. Ini berarti bahwa ketika pembaca pergi dan membaca artikel mereka hanya akan melihat satu penulis dalam artikel tersebut.
Misalnya: Artikel oleh John, Artikel oleh Harry, Artikel oleh Rick. Anda tidak dapat memiliki Artikel oleh Harry & Rick karena bos tidak ingin dua atau lebih penulis mengerjakan artikel yang sama.
Bagaimana kita bisa memecahkan 'masalah' ini dengan bantuan Django? Kunci untuk pemecahan masalah ini adalah Django ForeignKey
.
Berikut ini adalah kode lengkap yang dapat digunakan untuk menerapkan gagasan bos kami.
from django.db import models
# Create your models here.
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
def __unicode__(self):
return self.first_name
class Article(models.Model):
title = models.CharField(max_length=100)
reporter = models.ForeignKey(Reporter)
def __unicode__(self):
return self.title
Jalankan python manage.py syncdb
untuk mengeksekusi kode sql dan membangun tabel untuk aplikasi Anda di database Anda. Kemudian gunakan python manage.py shell
untuk membuka shell python.
Buat objek Reporter R1.
In [49]: from thepub.models import Reporter, Article
In [50]: R1 = Reporter(first_name='Rick')
In [51]: R1.save()
Buat objek Artikel A1.
In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)
In [6]: A1.save()
Kemudian gunakan potongan kode berikut untuk mendapatkan nama reporter.
In [8]: A1.reporter.first_name
Out[8]: 'Rick'
Sekarang buat objek Reporter R2 dengan menjalankan kode python berikut.
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
Sekarang coba tambahkan R2 ke objek Artikel A1.
In [13]: A1.reporter.add(R2)
Itu tidak bekerja dan Anda akan mendapatkan sebuah AttributeError yang mengatakan objek 'Reporter' tidak memiliki atribut 'tambah'.
Seperti yang Anda lihat objek Artikel tidak dapat dikaitkan dengan lebih dari satu objek Reporter.
Bagaimana dengan R1? Bisakah kita melampirkan lebih dari satu artikel objek ke dalamnya?
In [14]: A2 = Article.objects.create(title='Python News', reporter=R1)
In [15]: R1.article_set.all()
Out[15]: [<Article: Python News>, <Article: TDD In Django>]
Contoh praktis ini menunjukkan kepada kita bahwa Django ForeignKey
digunakan untuk mendefinisikan banyak-ke-satu hubungan.
OneToOneField
digunakan untuk membuat hubungan satu-ke-satu.
Kita dapat menggunakan reporter = models.OneToOneField(Reporter)
dalam file models.py di atas tetapi itu tidak akan berguna dalam contoh kita sebagai penulis tidak akan dapat memposting lebih dari satu artikel.
Setiap kali Anda ingin memposting artikel baru, Anda harus membuat objek Reporter baru. Ini menghabiskan waktu, bukan?
Saya sangat merekomendasikan untuk mencoba contohnya dengan OneToOneField
dan sadari perbedaannya. Saya cukup yakin bahwa setelah contoh ini Anda akan sepenuhnya mengetahui perbedaan antara Django OneToOneField
dan Django ForeignKey
.
OneToOneField (satu-ke-satu) menyadari, dalam orientasi objek, gagasan komposisi, sementara ForeignKey (satu-ke-banyak) berkaitan dengan persetujuan.
Patient
dan Organ
. Patient
dapat memiliki banyak Organ
s, tetapi Organ
kaleng hanya milik satu Patient
. Ketika Patient
dihapus, semua Organ
juga dihapus. Mereka tidak bisa eksis tanpa a Patient
.
Juga OneToOneField
berguna untuk digunakan sebagai kunci utama untuk menghindari duplikasi kunci. Seseorang mungkin tidak memiliki autofield implisit / eksplisit
models.AutoField(primary_key=True)
tetapi gunakan OneToOneField
sebagai kunci utama sebagai gantinya (bayangkan UserProfile
model misalnya):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
Ketika Anda mengakses OneToOneField Anda mendapatkan nilai dari bidang yang Anda tanyakan. Dalam contoh ini, bidang 'judul' model buku adalah OneToOneField:
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
Saat Anda mengakses ForeignKey, Anda mendapatkan objek model terkait, yang kemudian dapat Anda buat sebelumnya. Dalam contoh ini, bidang 'penerbit' model buku yang sama adalah ForeignKey (berkorelasi dengan definisi model kelas Penerbit):
>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'
Dengan bidang ForeignKey, kueri juga berfungsi sebaliknya, tetapi keduanya sedikit berbeda karena sifat hubungan yang tidak simetris.
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
Di belakang layar, book_set hanyalah QuerySet dan dapat difilter dan diiris seperti QuerySet lainnya. Nama atribut book_set dihasilkan dengan menambahkan nama model huruf kecil ke _set.
OneToOneField: jika tabel kedua terkait dengan
table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')
table2 hanya akan berisi satu record yang sesuai dengan nilai pk table1, yaitu table2_col1 akan memiliki nilai unik sama dengan pk tabel
table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')
table2 dapat berisi lebih dari satu record yang sesuai dengan nilai pk table1.