django OneToOneField和ForeignKey有什么区别?


Answers:


507

请注意,OneToOneField(SomeModel)和之间存在一些差异ForeignKey(SomeModel, unique=True)。如《 Django权威指南》所述:

一对一

一对一的关系。从概念上讲,这与ForeignKeywith 相似unique=True,但是关系的“反向”侧将直接返回单个对象。

OneToOneField“反向”关系相反,ForeignKey“反向”关系返回a 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 2013年

21
这个答案说“有一些差异”,然后说出一个差异。还有其他吗?
克里斯·马丁

6
我想和克里斯一样。它仅仅是语法糖,数据访问方式之间是否存在一些根本差异,从而导致性能差异?
卡洛斯(Carlos)

4
是否有根本原因导致Django无法拥有这样的规则,即如果外键是唯一的而不是null,那么它e.car也可以工作?
西罗Santilli郝海东冠状病六四事件法轮功

4
所以...什么时候甚至要使用ForeignKeywith unique=True而不是a OneToOneField?我在其他问题中看到Django甚至警告说,OneToOneField通常最好的服务是自己的利益。反向QuerySet永远不会有多个元素,对吗?
安迪

121

ForeignKey是一对多的,因此Car对象可能有多个Wheels,每个Wheel都具有与其所属的Car的ForeignKey。OneToOneField就像是Engine,其中Car对象可以只有一个并且只有一个。


4
谢谢,剂量OneToOneField(someModel)是指ForeignKey(SomeModel,unique = True)吗?
2011年

9
是的:“ OneToOneField本质上与ForeignKey相同,唯一的例外是,它始终带有“唯一”约束,并且反向关系始终返回指向的对象(因为将永远只有一个),而不是返回清单。”
丹·布雷恩

1
几辆具有相同发动机的汽车呢?
Oleg Belousov

3
@OlegTikhonov他们可能有相同引擎设计的副本,但我希望看到一个实例,其中有几辆汽车共享同一物理引擎。
丹·布雷恩

3
这个答案中的术语有些混乱。ForeignKey的是不是一到多,但它是根据官方的Django文档多到一的关系:docs.djangoproject.com/en/2.0/ref/models/fields/...
Kutay Demireren

45

学习新事物的最好,最有效的方法是查看和研究现实世界中的实例。假设您想在django中建立一个博客,让记者可以撰写和发布新闻文章。在线报纸的所有者希望允许他的每个记者根据需要发布任意数量的文章,但不希望其他记者从事同一篇文章。这意味着当读者去阅读一篇文章时,他们只会在文章中找到一位作者。

例如:John的文章,Harry的文章,Rick的文章。您不能拥有Harry&Rick的Article,因为老板不希望两个或多个作者撰写同一篇文章。

我们如何在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 syncdb以执行sql代码,并在数据库中为您的应用程序构建表。然后使用python manage.py shell打开python shell。

创建报告程序对象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'

现在,通过运行以下python代码创建Reporter对象R2。

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

In [10]: R2.save()

现在尝试将R2添加到商品对象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 用于创建一对一关系。

我们可以reporter = models.OneToOneField(Reporter)在上面的models.py文件中使用它,但是在我们的示例中该文件将无用,因为作者将不能发表多篇文章。

每次您要发布新文章时,都必须创建一个新的Reporter对象。这很费时间,不是吗?

我强烈建议您尝试使用的示例,OneToOneField并体会不同之处。我很确定,在此示例之后,您将完全了解django OneToOneField和django 之间的区别ForeignKey


我喜欢这个。OneToOne和ForeignKey之间的根本区别是一对一和一对多关系。您可以使用ForeignKey和unique = True一对一地进行操作,在Matthew的回复中指出了细微的差别。
FrankZhu

13

OneToOneField(一对一)以面向对象的方式实现组合的概念,而ForeignKey(一对多)与聚合有关。


3
很好的类比,但并非总是那样。有一些极端的情况不适合这种解释。举例来说,我们有类PatientOrganPatient可以有多个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时,您将获得相关的模型对象,然后可以对其执行进一步的查询。在此示例中,同一本书模型的“ publisher”字段是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。


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无法做到,并且不能附加到多个变量

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.