ความแตกต่างระหว่าง Django OneToOneField
และForeignKey
?
ความแตกต่างระหว่าง Django OneToOneField
และForeignKey
?
คำตอบ:
โปรดใช้ความระมัดระวังที่จะตระหนักว่ามีความแตกต่างบางอย่างระหว่างและOneToOneField(SomeModel)
ForeignKey(SomeModel, unique=True)
ตามที่ระบุไว้ในคู่มือการแตกหักเพื่อ Django :
OneToOneField
ความสัมพันธ์แบบหนึ่งต่อหนึ่ง แนวคิดนี้คล้าย
ForeignKey
กับด้วยunique=True
แต่ด้าน "ย้อนกลับ" ของความสัมพันธ์จะส่งคืนวัตถุเดียวโดยตรง
ในทางตรงกันข้ามกับOneToOneField
"ย้อนกลับ" ความสัมพันธ์เป็นForeignKey
"ย้อนกลับ" QuerySet
ความสัมพันธ์ผลตอบแทน
ตัวอย่างเช่นหากเรามีสองรุ่นต่อไปนี้ (รหัสรุ่นเต็มด้านล่าง):
Car
รูปแบบการใช้งาน OneToOneField(Engine)
Car2
รูปแบบการใช้งาน ForeignKey(Engine2, unique=True)
จากภายในpython manage.py shell
ดำเนินการดังต่อไปนี้:
OneToOneField
ตัวอย่าง>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>
ForeignKey
ด้วยunique=True
ตัวอย่าง>>> 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
ยังทำงาน?
ForeignKey
กับunique=True
มากกว่าOneToOneField
? ฉันเห็นในคำถามอื่น ๆ ที่ Django เตือนแม้กระทั่งว่าผลOneToOneField
ประโยชน์ของคนที่ดีที่สุดมักจะ การย้อนกลับQuerySet
จะไม่มีองค์ประกอบมากกว่าหนึ่งองค์ประกอบใช่ไหม
ForeignKey มีไว้สำหรับหนึ่งต่อหลายคนดังนั้นวัตถุรถยนต์อาจมีล้อหลายล้อแต่ละล้อที่มีกุญแจต่างประเทศเป็นของรถ OneToOneField จะเป็นเหมือนเครื่องมือที่วัตถุรถยนต์สามารถมีได้เพียงอันเดียว
วิธีที่ดีที่สุดและมีประสิทธิภาพมากที่สุดในการเรียนรู้สิ่งใหม่คือการดูและศึกษาตัวอย่างการใช้งานจริง สมมติว่าคุณต้องการสร้างบล็อกใน django สักครู่หนึ่งเพื่อให้นักข่าวสามารถเขียนและเผยแพร่บทความข่าวได้ เจ้าของหนังสือพิมพ์ออนไลน์ต้องการให้นักข่าวแต่ละคนของเขาเผยแพร่บทความได้มากเท่าที่ต้องการ แต่ไม่ต้องการให้นักข่าวต่างกันทำงานบทความเดียวกัน ซึ่งหมายความว่าเมื่อผู้อ่านไปและอ่านบทความพวกเขาจะเห็นผู้เขียนคนเดียวในบทความ
ตัวอย่างเช่น: บทความโดย John, บทความโดย Harry, บทความโดย Rick คุณไม่สามารถมีบทความโดย Harry & Rick เพราะหัวหน้าไม่ต้องการให้ผู้เขียนสองคนขึ้นไปทำงานในบทความเดียวกัน
เราจะแก้ปัญหานี้ด้วยความช่วยเหลือของ django ได้อย่างไร? กุญแจสำคัญในการแก้ปัญหาของปัญหานี้คือ ForeignKey
Django
ต่อไปนี้เป็นรหัสเต็มรูปแบบซึ่งสามารถใช้ในการใช้ความคิดของเจ้านายของเรา
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
รันpython manage.py syncdb
เพื่อรันโค้ด sql และสร้างตารางสำหรับแอปของคุณในฐานข้อมูลของคุณ จากนั้นใช้python manage.py shell
เพื่อเปิดเปลือกงูหลาม
สร้างวัตถุ Reporter R1
In [49]: from thepub.models import Reporter, Article
In [50]: R1 = Reporter(first_name='Rick')
In [51]: R1.save()
สร้างวัตถุบทความ A1
In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)
In [6]: A1.save()
จากนั้นใช้โค้ดต่อไปนี้เพื่อรับชื่อนักข่าว
In [8]: A1.reporter.first_name
Out[8]: 'Rick'
ตอนนี้สร้าง Reporter object R2 โดยรันรหัสไพ ธ อนต่อไปนี้
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
ทีนี้ลองเพิ่ม R2 ไปที่ Article Article A1
In [13]: A1.reporter.add(R2)
มันไม่ทำงานและคุณจะได้รับ AttributeError ว่าวัตถุ 'Reporter' ไม่มีแอตทริบิวต์ 'เพิ่ม'
ในขณะที่คุณสามารถเห็นวัตถุบทความไม่สามารถเกี่ยวข้องกับวัตถุผู้สื่อข่าวมากกว่าหนึ่ง
แล้ว R1 ล่ะ เราสามารถแนบวัตถุของบทความมากกว่าหนึ่งวัตถุได้หรือไม่
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>]
ตัวอย่างการปฏิบัตินี้แสดงให้เราเห็นว่า django ForeignKey
ใช้เพื่อกำหนดความสัมพันธ์แบบหนึ่งต่อหนึ่ง
OneToOneField
ใช้เพื่อสร้างความสัมพันธ์แบบหนึ่งต่อหนึ่ง
เราสามารถใช้reporter = models.OneToOneField(Reporter)
ในไฟล์ models.py ข้างต้น แต่มันจะไม่เป็นประโยชน์ในตัวอย่างของเราเนื่องจากผู้เขียนจะไม่สามารถโพสต์บทความมากกว่าหนึ่งบทความ
ทุกครั้งที่คุณต้องการโพสต์บทความใหม่คุณจะต้องสร้างวัตถุ Reporter ใหม่ ใช้เวลานานใช่มั้ย
ฉันขอแนะนำให้ลองตัวอย่างด้วยOneToOneField
และตระหนักถึงความแตกต่าง ผมค่อนข้างแน่ใจว่าหลังจากที่ตัวอย่างนี้คุณสมบูรณ์จะทราบความแตกต่างระหว่าง Django OneToOneField
และ ForeignKey
Django
OneToOneField (หนึ่งต่อหนึ่ง) ตระหนักถึงการวางแนวของวัตถุความคิดของการจัดองค์ประกอบในขณะที่ ForeignKey (หนึ่งต่อหลายคน) เกี่ยวข้องกับ agregation
Patient
สามารถมีหลายs แต่สามารถอยู่เพียงคนเดียว เมื่อถูกลบs ทั้งหมดจะถูกลบด้วย พวกเขาไม่สามารถอยู่ได้โดยไม่ต้อง Organ
Patient
Organ
Organ
Patient
Patient
Organ
Patient
นอกจากนี้ยังOneToOneField
มีประโยชน์ที่จะใช้เป็นคีย์หลักเพื่อหลีกเลี่ยงการทำสำเนาคีย์ อย่างใดอย่างหนึ่งอาจไม่มีการเปิดเผยอัตโนมัติโดยนัย / ชัดเจน
models.AutoField(primary_key=True)
แต่ใช้OneToOneField
เป็นคีย์หลักแทน (ลองนึกภาพUserProfile
รุ่นเป็นต้น):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
เมื่อคุณเข้าถึง OneToOneField คุณจะได้รับค่าของฟิลด์ที่คุณสอบถาม ในตัวอย่างนี้ฟิลด์ 'ชื่อเรื่อง' ของรูปแบบหนังสือคือ OneToOneField:
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
เมื่อคุณเข้าถึง ForeignKey คุณจะได้รับวัตถุโมเดลที่เกี่ยวข้องซึ่งคุณสามารถ preform แบบสอบถามเพิ่มเติมได้ ในตัวอย่างนี้ฟิลด์ 'ผู้จัดพิมพ์' ของรูปแบบหนังสือเล่มเดียวกันคือ ForeignKey (สัมพันธ์กับคำจำกัดความของรูปแบบคลาสสำนักพิมพ์)
>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'
ด้วยการค้นหาเขตข้อมูล ForeignKey ก็ใช้วิธีอื่นเช่นกัน แต่ก็แตกต่างกันเล็กน้อยเนื่องจากลักษณะความสัมพันธ์ที่ไม่สมมาตร
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
book_set เป็นฉากหลังของฉากและสามารถกรองและแบ่งย่อยเป็นชุดอื่น ๆ ได้ ชื่อแอ็ตทริบิวต์ book_set ถูกสร้างขึ้นโดยต่อท้ายชื่อโมเดลตัวพิมพ์เล็กเป็น _set
OneToOneField: หากตารางที่สองเกี่ยวข้องกับ
table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')
table2 จะมีเพียงหนึ่งระเบียนที่สอดคล้องกับค่า pk ของ table1 เช่น table2_col1 จะมีค่าที่ไม่ซ้ำกันเท่ากับ pk ของตาราง
table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')
table2 อาจมีมากกว่าหนึ่งบันทึกที่สอดคล้องกับค่า pk ของ table1
ForeignKey อนุญาตให้คุณรับคลาสย่อยคือนิยามของคลาสอื่น แต่ OneToOneFields ไม่สามารถทำได้และไม่สามารถแนบกับตัวแปรหลายตัวได้