Django中的OneToOneField()与ForeignKey()
Django中的OneToOneField
和ForeignKey
有什么区别呢?
12 个回答
学习新东西最有效的方法就是看看真实的例子,研究一下实际的应用场景。假设你想用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的OneToOneField
和ForeignKey
之间的区别。
一个 ForeignKey
是一种多对一的关系。也就是说,一个 Car
对象可以有很多个 Wheel
实例。而每个 Wheel
都会有一个 ForeignKey
指向它所属的 Car
。而 OneToOneField
就像是 Engine
的实例,一个 Car
对象最多只能有一个引擎,也就是说只能有一个。
关于 OneToOneField(SomeModel)
和 ForeignKey(SomeModel, unique=True)
的区别,参考了《Django权威指南》:
OneToOneField
这是一种一对一的关系。简单来说,它和带有
unique=True
的ForeignKey
有点像,但在“反向”关系中,它会直接返回一个单独的对象。
与 OneToOneField
的“反向”关系不同,ForeignKey
的“反向”关系会返回一个 QuerySet
,也就是一组对象。
例子
比如,我们有以下两个模型(完整的模型代码在下面):
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