django OneToOneField와 ForeignKey의 차이점은 무엇입니까?


답변:


507

OneToOneField(SomeModel)와 사이에 약간의 차이가 있음을주의하십시오 ForeignKey(SomeModel, unique=True). 장고대한 결정적인 가이드에 명시된 바와 같이 :

OneToOneField

일대일 관계. 개념적으로 이것은 ForeignKeywith와 비슷 unique=True하지만 관계의 "역"면이 단일 객체를 직접 반환합니다.

OneToOneField"역방향"관계 와 달리 ForeignKey"역방향"관계는을 반환합니다 QuerySet.

예를 들어 다음 두 가지 모델이있는 경우 (아래의 전체 모델 코드) :

  1. Car 모델 용도 OneToOneField(Engine)
  2. 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>

ForeignKeyunique=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

5
@MarkPNeyer : 내가 이해하는 한 OneToOne 필드는 일대일입니다. 위에있을 필요는 없습니다. 이 예를 참조하십시오 . 장소는 식당 일 필요는 없습니다.
osa

21
이 대답은 "일부 차이가 있습니다"라고 말한 다음 한 가지 차이점을 말합니다. 다른 사람이 있습니까?
Chris Martin

6
크리스와 똑같은 것이 궁금합니다. 그것은 단순히 구문상의 설탕입니까? 데이터에 액세스하는 방법에 근본적인 차이가 있습니까? 성능 차이가 있습니까?
Carlos

4
Django가 외래 키가 고유하고 null이 아닌 경우 작동하는 규칙을 가질 수없는 근본적인 이유 e.car가 있습니까?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

4
그래서 ... 때 일조차를 사용할 것 ForeignKey으로 unique=True보다는 OneToOneField? 다른 질문에서 Django는 OneToOneField일반적으로 최선을 다하는 것이 자신의 이익 이라고 경고합니다 . 그 반대 QuerySet는 하나 이상의 요소를 가지지 않을 것입니다.
Andy

121

ForeignKey는 일대 다용이므로 Car 객체에는 여러 개의 Wheel이있을 수 있으며 각 Wheel에는 해당 Wheel에 대한 ForeignKey가 있습니다. OneToOneField는 Car 객체가 하나만 가질 수있는 Engine과 같습니다.


4
감사합니다. Dose OneToOneField (someModel)는 ForeignKey (SomeModel, unique = True)를 의미합니까?
redice

9
예 : 'OneToOneField는 본질적으로 ForeignKey와 동일합니다. 단, 항상 "고유 한"제약 조건이 적용되고 역 관계는 ​​항상 (단 하나만 있기 때문에) a를 반환하지 않고 지정된 객체를 반환합니다. 명부.'
Dan Breen

1
같은 엔진을 가진 몇 대의 자동차는 어떻습니까?
Oleg Belousov

3
@OlegTikhonov 그들은 동일한 엔진 디자인 의 사본 을 가지고있을 수도 있지만 여러 자동차가 동일한 물리적 엔진을 공유하는 인스턴스를보고 싶습니다.
Dan Breen

3
이 답변의 용어에 대해서는 약간의 혼란이 있습니다. ForeignKey는 일대 다가 아니지만 공식 django 문서에 따르면 다 대일
Kutay Demireren

45

새로운 것을 배우는 가장 효과적이고 효과적인 방법은 실제 실제 사례를보고 연구하는 것입니다. 기자가 뉴스 기사를 쓰고 게시 할 수있는 django에서 블로그를 작성하려고한다고 가정하십시오. 온라인 신문의 소유자는 자신의 각 기자가 원하는만큼 많은 기사를 게시 할 수 있기를 원하지만 다른 기사가 동일한 기사를 작성하는 것을 원하지 않습니다. 이는 독자가 기사를 읽고 읽을 때 기사에서 한 명의 작성자 만 선택한다는 것을 의미합니다.

예 : John의 기사, Harry의 기사, Rick의 기사. 상사는 두 명 이상의 저자가 같은 기사를 작업하기를 원하지 않기 때문에 Harry & Rick의 기사를 가질 수 없습니다.

django의 도움으로이 '문제'를 어떻게 해결할 수 있습니까? 이 문제의 해결의 열쇠는 django ForeignKey입니다.

다음은 보스의 아이디어를 구현하는 데 사용할 수있는 전체 코드입니다.

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 syncdbSQL 코드를 실행하고 데이터베이스에 앱 테이블을 구축 할 수 있습니다. 그런 다음 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 오브젝트 R2를 작성하십시오.

In [9]: R2 = Reporter.objects.create(first_name='Harry')

In [10]: R2.save()

이제 Article 객체 A1에 R2를 추가하십시오.

In [13]: A1.reporter.add(R2)

작동하지 않으며 'Reporter'개체에 'add'속성이 없다고 말하는 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>]

이 실제 예는 장고 ForeignKey가 다 대일 관계를 정의하는 데 사용됨을 보여줍니다 .

OneToOneField 일대일 관계를 만드는 데 사용됩니다.

reporter = models.OneToOneField(Reporter)위의 models.py 파일에서 사용할 수 있지만 작성자가 두 개 이상의 기사를 게시 할 수 없으므로이 예에서는 유용하지 않습니다.

새 기사를 게시 할 때마다 새 Reporter 개체를 만들어야합니다. 이것은 시간이 걸리지 않습니까?

나는 함께 예제를 시도 OneToOneField하고 차이점을 깨닫는 것이 좋습니다 . 이 예제를 마치면 django OneToOneField와 django 의 차이점을 완전히 알게 될 것 ForeignKey입니다.


나는 이것을 좋아한다. OneToOne과 ForeignKey의 근본적인 차이점은 일대일 관계입니다. ForeignKey와 unique = True를 사용하여 일대일로 할 수 있습니다. 미묘한 차이점은 Matthew의 답변에 나와 있습니다.
FrankZhu

13

OneToOneField (일대일)는 객체 지향에서 컴포지션의 개념을 인식하는 반면 ForeignKey (일대 다)는 집계와 관련됩니다.


3
좋은 비유이지만 항상 그런 것은 아닙니다. 이 설명에 맞지 않는 일부 경우가 있습니다. 예를 들어 보자 말 우리는 수업을 Patient하고 Organ. Patient은 여러 개를 가질 수 Organ있지만 Organ하나만 가질 수 있습니다 Patient. 때 Patient삭제, 모두 Organ들 너무 삭제됩니다. 없이는 존재할 수 없습니다 Patient.
cezar

4

또한 OneToOneField키 중복을 피하기 위해 기본 키로 사용하기에 유용하다. 암시 적 / 명시 적 자동 필드가 없을 수 있습니다

models.AutoField(primary_key=True)

하지만 사용 OneToOneField하는 대신 기본 키는 (상상 UserProfile예를 들어 모델) :

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')

3

OneToOneField에 액세스하면 쿼리 한 필드의 값을 얻습니다. 이 예에서 책 모델의 '제목'필드는 OneToOneField입니다.

>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'

ForeignKey에 액세스하면 관련 모델 개체가 생성되어 추가 쿼리를 수행 할 수 있습니다. 이 예에서 동일한 책 모델의 '게시자'필드는 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은 QuerySet 일 뿐이며 다른 QuerySet처럼 필터링 및 슬라이스 할 수 있습니다. book_set 속성 이름은 _set에 소문자 모델 이름을 추가하여 생성됩니다.


1

OneToOneField : 두 번째 테이블이 관련된 경우

table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')

table2는 table1의 pk 값에 해당하는 하나의 레코드 만 포함합니다. 즉 table2_col1은 table의 pk와 동일한 고유 값을 갖습니다.

table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')

table2는 table1의 pk 값에 해당하는 둘 이상의 레코드를 포함 할 수 있습니다.


1

ForeignKey는 서브 클래스를 수신 할 수 있도록 허용합니다. 다른 클래스의 정의이지만 OneToOneFields는이를 수행 할 수 없으며 여러 변수에 첨부 할 수 없습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.