Django中的OneToOneField()与ForeignKey()

562 投票
12 回答
201490 浏览
提问于 2025-04-16 16:54

Django中的OneToOneFieldForeignKey有什么区别呢?

12 个回答

72

学习新东西最有效的方法就是看看真实的例子,研究一下实际的应用场景。假设你想用Django搭建一个博客,让记者们可以写和发布新闻文章。在线报纸的老板希望每位记者都能发布尽可能多的文章,但不希望不同的记者在同一篇文章上合作。这意味着,当读者阅读一篇文章时,只能看到一个作者的名字。

举个例子:文章由约翰撰写,文章由哈利撰写,文章由里克撰写。你不能有“文章由哈利和里克撰写”,因为老板不希望有两个或更多的作者共同撰写同一篇文章。

那么,我们如何用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命令行。

创建一个记者对象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代码来创建记者对象R2。

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

In [10]: R2.save()

现在尝试将R2添加到文章对象A1中。

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

这不行,你会得到一个属性错误,提示“'Reporter'对象没有'add'属性”。

正如你所看到的,一篇文章对象不能关联多个记者对象。

那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>]

这个实际例子告诉我们,Django的ForeignKey用于定义多对一的关系。

OneToOneField用于创建一对一的关系。

我们可以在上面的models.py文件中使用reporter = models.OneToOneField(Reporter),但在我们的例子中这并没有用,因为一个作者不能发布多于一篇文章。

每次你想发布新文章时,都得创建一个新的记者对象。这可真费时间,不是吗?

我强烈建议你尝试用OneToOneField的例子,感受一下其中的不同。我相信,通过这个例子,你会完全明白Django的OneToOneFieldForeignKey之间的区别。

184

一个 ForeignKey 是一种多对一的关系。也就是说,一个 Car 对象可以有很多个 Wheel 实例。而每个 Wheel 都会有一个 ForeignKey 指向它所属的 Car。而 OneToOneField 就像是 Engine 的实例,一个 Car 对象最多只能有一个引擎,也就是说只能有一个。

663

关于 OneToOneField(SomeModel)ForeignKey(SomeModel, unique=True) 的区别,参考了《Django权威指南》

OneToOneField

这是一种一对一的关系。简单来说,它和带有 unique=TrueForeignKey 有点像,但在“反向”关系中,它会直接返回一个单独的对象。

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

撰写回答