django OneToOneField和ForeignKey有什么区别?

时间:2011-05-03 13:54:18

标签: django django-models

django OneToOneField和ForeignKey有什么区别?

11 个答案:

答案 0 :(得分:426)

请注意OneToOneField(SomeModel)ForeignKey(SomeModel, unique=True)之间存在一些差异。如The Definitive Guide to Django中所述:

  

<强> OneToOneField

     

一对一的关系。从概念上讲,这类似于ForeignKey unique=True,但关系的“反向”将直接返回单个对象。

OneToOneField“反向”关系相反,ForeignKey“反向”关系会返回QuerySet

实施例

例如,如果我们有以下两个模型(下面的完整模型代码):

  1. Car模型使用OneToOneField(Engine)
  2. Car2模型使用ForeignKey(Engine2, unique=True)
  3. 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
    

答案 1 :(得分:94)

ForeignKey用于一对多,因此Car对象可能有许多Wheels,每个Wheel对其所属的Car具有ForeignKey。 OneToOneField就像一个引擎,Car对象只能有一个。

答案 2 :(得分:30)

学习新事物的最佳和最有效的方法是查看和研究现实世界的实际例子。假设你想在django建立一个博客,记者可以在那里撰写和发布新闻文章。在线报纸的所有者希望允许他的每个记者发布尽可能多的文章,但不希望不同的记者在同一篇文章上工作。这意味着当读者去阅读文章时,他们将只会在文章中找到一位作者。

例如:John的文章,Harry的文章,Rick的文章。哈利&amp;你不能拥有文章。瑞克,因为老板不希望两个或更多的作者在同一篇文章上工作。

我们如何解决这个问题&#39;在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。

创建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'

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

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

In [10]: R2.save()

现在尝试将R2添加到Article对象A1。

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

它不起作用,你会得到一个描述&#39; Reporter&#39;对象没有属性&#39;添加&#39;。

正如您所看到的,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对象。这很费时间,不是吗?

我强烈建议您使用OneToOneField尝试示例,并意识到差异。我很确定在这个例子之后你将完全知道django OneToOneField和django ForeignKey之间的区别。

答案 3 :(得分:11)

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

答案 4 :(得分:2)

当您访问OneToOneField时,您将获得所查询字段的值。在此示例中,图书模型的“标题”字段是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

答案 5 :(得分:2)

此外,OneToOneField可用作主键以避免密钥重复。一个人可能没有隐式/显式自动屏幕

models.AutoField(primary_key=True)

但是使用OneToOneField作为主键(例如,想象UserProfile模型):

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

答案 6 :(得分:1)

我也对这两个字段的用法感到困惑。 我举个例子来理解它们的用法,因为我最近遇到了这个问题,并且意识到了这两个字段的用法。

我有一个模型,像这样-

from django.contrib.auth.models import User
from django.db import models


class Attendance(models.Model):
     user = models.OneToOneField(User, on_delete=models.CASCADE, default="", null=True)
     date = models.CharField(max_length=11)

     def __int__(self):
         return self.id

现在的问题是我不能用同一个用户创建多个对象, 即同一用户将出席多天。因此,具有相同用户的多个对象。

但是 OneToOne 字段不允许我这样做。 Image for reference

所以,我将模型更改为-

from django.contrib.auth.models import User
from django.db import models


class Attendance(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, default="", null=True)
    date = models.CharField(max_length=11)

    def __int__(self):
        return self.id

现在它工作正常,我可以为用户标记多天的出席情况。

所以这就是不同之处,OneToOne 字段不允许您使用同一用户创建多个对象(例如),但使用 ForeignKey 是可能的。

答案 7 :(得分:0)

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值相对应的记录。

答案 8 :(得分:0)

ForeignKey允许您接收子类,因为它是另一个类的定义,但是OneToOneFields无法做到这一点,并且不能附加到多个变量

答案 9 :(得分:0)

在项目之间建立关系的最简单方法是通过使用简单的语言来理解它们。例子

用户可以拥有多辆汽车,但是一辆汽车只能拥有一个所有者。建立此关系后,应在具有许多关系的项目上使用外键。在这种情况下是汽车。意味着您会将用户作为外键包含在汽车中

一对一的关系非常简单。说一个男人和一颗心。一个人只有一颗心,一颗心只能属于一个人

答案 10 :(得分:0)

OneToOneField(例如:一辆车有一个主人) ForeignKey(OneToMany)(例如:一家餐厅有很多项目)