回答:
いくつかの違いがあることを実感するように注意してくださいOneToOneField(SomeModel)
とはForeignKey(SomeModel, unique=True)
。Djangoの決定的なガイドで述べたように:
OneToOneField
1対1の関係。概念的には、これは
ForeignKey
withunique=True
に似ていますが、関係の「逆」側は直接単一のオブジェクトを返します。
OneToOneField
「逆」関係とは対照的に、「ForeignKey
逆」関係はを返しますQuerySet
。
たとえば、次の2つのモデルがある場合(以下の完全なモデルコード):
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
with を使用したいのunique=True
はOneToOneField
いつですか?他の質問では、DjangoがOneToOneField
通常は最善のサービスを自分の利益に提供することを警告していることもあります。逆QuerySet
は、複数の要素を持つことはありませんよね?
ForeignKeyは1対多のものであるため、Carオブジェクトには多数のホイールがあり、各ホイールには所属するCarへのForeignKeyがあります。OneToOneFieldはエンジンのようなもので、Carオブジェクトは1つだけ持つことができます。
新しいことを学ぶための最良かつ最も効果的な方法は、実際の実例を見て研究することです。とりあえず、記者がニュース記事を書いて公開できるdjangoでブログを構築したいとします。オンライン新聞の所有者は、各記者が必要なだけ多くの記事を発行できるようにしたいと考えていますが、同じ記事に対して別の記者が作業することは望んでいません。これは、読者が記事を読み読みするときに、記事の著者は1人だけであることを意味します。
例:Johnによる記事、Harryによる記事、Rickによる記事。上司は2人以上の著者に同じ記事での作業を望まないため、Harry&Rickによる記事を作成することはできません。
ジャンゴの助けを借りて、この「問題」をどのように解決できますか?この問題を解決する鍵は、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 syncdb
してSQLコードを実行し、データベースにアプリのテーブルを作成します。次に、を使用python manage.py shell
してPythonシェルを開きます。
ReporterオブジェクトR1を作成します。
In [49]: from thepub.models import Reporter, Article
In [50]: R1 = Reporter(first_name='Rick')
In [51]: R1.save()
Articleオブジェクト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'
次のPythonコードを実行して、ReporterオブジェクトR2を作成します。
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
次に、R2をArticleオブジェクトA1に追加します。
In [13]: A1.reporter.add(R2)
これは機能せず、「Reporter」オブジェクトに属性「add」がないことを示すAttributeErrorが表示されます。
ご覧のとおり、Articleオブジェクトを複数のReporterオブジェクトに関連付けることはできません。
R1はどうですか?複数のArticleオブジェクトをそれにアタッチできますか?
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
が多対1の関係を定義するために使用されていることを示しています。
OneToOneField
1対1の関係を作成するために使用されます。
reporter = models.OneToOneField(Reporter)
上記のmodels.pyファイルで使用できますが、作成者は複数の記事を投稿できないため、この例では役に立ちません。
新しい記事を投稿するたびに、新しいReporterオブジェクトを作成する必要があります。これは時間がかかりますね。
で例を試してOneToOneField
、違いを理解することを強くお勧めします。この例の後で、django OneToOneField
とdjangoの違いが完全にわかると思いますForeignKey
。
またOneToOneField
、キーの重複を回避するために主キーとして使用すると便利です。暗黙的/明示的な自動フィールドがない場合があります
models.AutoField(primary_key=True)
OneToOneField
代わりに主キーとして使用してください(UserProfile
たとえば、モデルを想像してください):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
OneToOneFieldにアクセスすると、照会したフィールドの値を取得します。この例では、書籍モデルの「title」フィールドはOneToOneFieldです。
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
ForeignKeyにアクセスすると、関連するモデルオブジェクトが取得されます。このオブジェクトを使用して、さらにクエリを実行できます。この例では、同じ本モデルの 'publisher'フィールドは、(Publisherクラスモデル定義に対応する)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に追加することによって生成されます。
OneToOneField:2番目のテーブルが関連付けられている場合
table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')
table2には、table1のpk値に対応するレコードが1つだけ含まれます。つまり、table2_col1には、テーブルのpkに等しい一意の値が含まれます。
table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')
table2には、table1のpk値に対応する複数のレコードが含まれる場合があります。