Django OneToOneField
和 ForeignKey
有什么区别?
The Definitive Guide to Django 中所述的 OneToOneField(SomeModel)
和 ForeignKey(SomeModel, unique=True)
之间的区别:
OneToOneField 一对一的关系。从概念上讲,这类似于具有 unique=True 的 ForeignKey,但关系的“反向”侧将直接返回单个对象。
与 OneToOneField
“反向”关系相反,ForeignKey
“反向”关系返回 QuerySet
。
例子
例如,如果我们有以下两个模型(完整模型代码如下):
汽车模型使用 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>
具有 unique=True 示例的 ForeignKey
>>> 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
对象可能有许多 Wheel
实例。因此,每个 Wheel
都会有一个 ForeignKey
到它所属的 Car
。 OneToOneField
类似于 Engine
的实例,其中 Car
对象至多只有一个且只有一个。
学习新事物的最好和最有效的方法是查看和研究现实世界的实际例子。假设您想在 django 中建立一个博客,记者可以在其中撰写和发布新闻文章。在线报纸的所有者希望允许他的每个记者发布任意数量的文章,但不希望不同的记者在同一篇文章上工作。这意味着当读者阅读一篇文章时,他们只会在文章中看到一位作者。
例如:John 的文章、Harry 的文章、Rick 的文章。您不能拥有 Harry & Rick 的文章,因为老板不希望两个或多个作者在同一篇文章上工作。
我们如何在 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 对象 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呢?我们可以将多个文章对象附加到它吗?
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
之间的区别。
OneToOneField(一对一)在面向对象中实现了组合的概念,而 ForeignKey(一对多)与聚合有关。
Patient
和 Organ
。 Patient
可以有多个 Organ
,但一个 Organ
只能属于一个 Patient
。当 Patient
被删除时,所有的 Organ
也被删除。如果没有 Patient
,它们就无法存在。
此外,OneToOneField
可用作主键以避免键重复。一个可能没有隐式/显式自动字段
models.AutoField(primary_key=True)
但使用 OneToOneField
作为主键(例如 UserProfile
模型):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
当您访问 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 一样进行过滤和切片。属性名称 book_set 是通过将小写模型名称附加到 _set 来生成的。
我也对这两个字段的用法感到困惑。让我举一个例子来了解它们的用法,因为我最近遇到了这个问题并意识到了这两个字段的用法。
我有一个模型,像这样-
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 是可能的。
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 值对应的记录。
绘制项目之间关系的最简单方法是用通俗易懂的语言理解它们。例子
一个用户可以拥有多辆汽车,但一辆汽车只能拥有一个车主。建立这个之后,外键应该用在具有多关系的项目上。在这种情况下,汽车。这意味着您将在汽车中包含用户作为外键
一对一的关系非常简单。说一个人和一颗心。一个人只有一颗心,一颗心只能属于一个人
OneToOneField (示例:一辆车有一个所有者) ForeignKey(OneToMany) (示例:一家餐厅有很多项目)
ForeignKey 允许您接收子类,它是另一个类的定义,但 OneToOneFields 不能这样做,并且它不能附加到多个变量
不定期副业成功案例分享
ForeignKey
与unique=True
而不是OneToOneField
一起使用?我在其他问题中看到 Django 甚至警告说OneToOneField
通常最符合自己的利益。反向QuerySet
永远不会有多个元素,对吧?