django OneToOneField和ForeignKey有什么区别?
请注意 OneToOneField(SomeModel) 和 ForeignKey(SomeModel, unique=True) 之间存在一些差异 . 如The Definitive Guide to Django所述:
OneToOneField(SomeModel)
ForeignKey(SomeModel, unique=True)
OneToOneField一对一的关系 . 从概念上讲,这类似于具有唯一= True的ForeignKey,但关系的“反向”侧将直接返回单个对象 .
与 OneToOneField "reverse"关系相反, ForeignKey "reverse"关系返回 QuerySet .
OneToOneField
ForeignKey
QuerySet
例如,如果我们有以下两个模型(下面的完整模型代码):
Car 型号使用 OneToOneField(Engine)
Car
OneToOneField(Engine)
Car2 型号使用 ForeignKey(Engine2, unique=True)
Car2
ForeignKey(Engine2, unique=True)
从 python manage.py shell 内执行以下操作:
python manage.py shell
>>> from testapp.models import Car, Engine >>> c = Car.objects.get(name='Audi') >>> e = Engine.objects.get(name='Diesel') >>> e.car <Car: Audi>
>>> 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
ForeignKey用于一对多,因此Car对象可能具有许多Wheels,每个Wheel对其所属的Car具有ForeignKey . OneToOneField就像一个引擎,其中一个Car对象只能有一个 .
学习新事物的最佳和最有效的方法是查看和研究现实世界的实际例子 . 假设你想在django Build 一个博客,记者可以在那里撰写和发布新闻文章 . 在线报纸的所有者希望允许他的每个记者发布尽可能多的文章,但不希望不同的记者在同一篇文章上工作 . 这意味着当读者去阅读文章时,他们将只会在文章中找到一位作者 .
例如:John的文章,Harry的文章,Rick的文章 . 你不能拥有Harry&Rick的文章,因为老板不希望两个或更多的作者在同一篇文章上工作 .
我们如何在django的帮助下解决这个'problem'?解决这个问题的关键是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 shell .
python manage.py syncdb
创建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)
它不起作用,你会得到一个AttributeError,说'Reporter'对象没有属性'add' .
如您所见,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 用于定义多对一关系 .
OneToOneField 用于创建一对一关系 .
我们可以在上面的models.py文件中使用 reporter = models.OneToOneField(Reporter) ,但在我们的示例中它不会有用,因为作者将无法发布多篇文章 .
reporter = models.OneToOneField(Reporter)
每次要发布新文章时,都必须创建一个新的Reporter对象 . 这很耗时,不是吗?
我强烈建议尝试使用 OneToOneField 的示例并实现差异 . 我很确定在这个例子之后你将完全知道django OneToOneField 和django ForeignKey 之间的区别 .
OneToOneField(一对一)以面向对象的方式实现组合的概念,而ForeignKey(一对多)则与聚合有关 .
当您访问OneToOneField时,您将获得所查询字段的值 . 在此示例中,图书模型的“ Headers ”字段是OneToOneField:
>>> from mysite.books.models import Book >>> b = Book.objects.get(id=50) >>> b.title u'The Django Book'
当您访问ForeignKey时,您将获得相关的模型对象,然后您可以对其进行进一步的查询 . 在此示例中,相同图书模型的“发布者”字段是ForeignKey(与Publisher类模型定义相关):
>>> 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一样进行过滤和切片 . 通过将小写模型名称附加到_set来生成属性名称book_set .
此外, OneToOneField 可用作主键以避免密钥重复 . 一个人可能没有隐式/显式自动对话
models.AutoField(primary_key=True)
但是使用 OneToOneField 作为主键(例如,想象 UserProfile 模型):
UserProfile
user = models.OneToOneField( User, null=False, primary_key=True, verbose_name='Member profile')
6 回答
请注意
OneToOneField(SomeModel)
和ForeignKey(SomeModel, unique=True)
之间存在一些差异 . 如The Definitive Guide to Django所述:与
OneToOneField
"reverse"关系相反,ForeignKey
"reverse"关系返回QuerySet
.示例
例如,如果我们有以下两个模型(下面的完整模型代码):
Car
型号使用OneToOneField(Engine)
Car2
型号使用ForeignKey(Engine2, unique=True)
从
python manage.py shell
内执行以下操作:OneToOneField示例
ForeignKey with unique = True示例
型号代码
ForeignKey用于一对多,因此Car对象可能具有许多Wheels,每个Wheel对其所属的Car具有ForeignKey . OneToOneField就像一个引擎,其中一个Car对象只能有一个 .
学习新事物的最佳和最有效的方法是查看和研究现实世界的实际例子 . 假设你想在django Build 一个博客,记者可以在那里撰写和发布新闻文章 . 在线报纸的所有者希望允许他的每个记者发布尽可能多的文章,但不希望不同的记者在同一篇文章上工作 . 这意味着当读者去阅读文章时,他们将只会在文章中找到一位作者 .
例如:John的文章,Harry的文章,Rick的文章 . 你不能拥有Harry&Rick的文章,因为老板不希望两个或更多的作者在同一篇文章上工作 .
我们如何在django的帮助下解决这个'problem'?解决这个问题的关键是django
ForeignKey
.以下是可用于实现我们老板想法的完整代码 .
运行
python manage.py syncdb
以执行sql代码并在数据库中为您的应用程序构建表 . 然后使用python manage.py shell
打开python shell .创建Reporter对象R1 .
创建Article对象A1 .
然后使用以下代码获取报告者的名称 .
现在通过运行以下python代码创建Reporter对象R2 .
现在尝试将R2添加到Article对象A1 .
它不起作用,你会得到一个AttributeError,说'Reporter'对象没有属性'add' .
如您所见,Article对象不能与多个Reporter对象相关 .
R1怎么样?我们可以附加多个Article对象吗?
这个实际例子向我们展示了django
ForeignKey
用于定义多对一关系 .OneToOneField
用于创建一对一关系 .我们可以在上面的models.py文件中使用
reporter = models.OneToOneField(Reporter)
,但在我们的示例中它不会有用,因为作者将无法发布多篇文章 .每次要发布新文章时,都必须创建一个新的Reporter对象 . 这很耗时,不是吗?
我强烈建议尝试使用
OneToOneField
的示例并实现差异 . 我很确定在这个例子之后你将完全知道djangoOneToOneField
和djangoForeignKey
之间的区别 .OneToOneField(一对一)以面向对象的方式实现组合的概念,而ForeignKey(一对多)则与聚合有关 .
当您访问OneToOneField时,您将获得所查询字段的值 . 在此示例中,图书模型的“ Headers ”字段是OneToOneField:
当您访问ForeignKey时,您将获得相关的模型对象,然后您可以对其进行进一步的查询 . 在此示例中,相同图书模型的“发布者”字段是ForeignKey(与Publisher类模型定义相关):
使用ForeignKey字段查询也是相反的,但由于关系的非对称性,它们略有不同 .
在幕后,book_set只是一个QuerySet,可以像任何其他QuerySet一样进行过滤和切片 . 通过将小写模型名称附加到_set来生成属性名称book_set .
此外,
OneToOneField
可用作主键以避免密钥重复 . 一个人可能没有隐式/显式自动对话但是使用
OneToOneField
作为主键(例如,想象UserProfile
模型):