Django 中的 OneToOneField() 与foreignkey()

发布于 2024-11-04 19:16:09 字数 75 浏览 3 评论 0原文

Django OneToOneFieldForeignKey 之间有什么区别?

What's the difference between Django OneToOneField and ForeignKey?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

是你 2024-11-11 19:16:09

OneToOneField(SomeModel)ForeignKey(SomeModel, unique=True) 之间的差异,如 Django 权威指南

OneToOneField

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

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

示例

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

  1. Car 模型使用 OneToOneField(Engine)
  2. Car2 模型使用 < code>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

Differences between OneToOneField(SomeModel) and ForeignKey(SomeModel, unique=True) as stated in The Definitive Guide to Django:

OneToOneField

A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the "reverse" side of the relation will directly return a single object.

In contrast to the OneToOneField "reverse" relation, a ForeignKey "reverse" relation returns a QuerySet.

Example

For example, if we have the following two models (full model code below):

  1. Car model uses OneToOneField(Engine)
  2. Car2 model uses ForeignKey(Engine2, unique=True)

From within python manage.py shell execute the following:

OneToOneField Example

>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>

ForeignKey with unique=True Example

>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]

Model Code

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
小红帽 2024-11-11 19:16:09

ForeignKey 是多对一关系。因此,Car 对象可能有许多 Wheel 实例。因此,每个 Wheel 都会有一个指向其所属 CarForeignKeyOneToOneField 就像 Engine 的一个实例,其中 Car 对象有至多一个且仅有一个。

A ForeignKey is a many-to-one relationship. So, a Car object might have many instances of Wheel. Each Wheel would consequently have a ForeignKey to the Car it belongs to. A OneToOneField would be like an instance of Engine, where a Car object has at most one and only one.

作业与我同在 2024-11-11 19:16:09

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

例如:约翰的文章、哈利的文章、里克的文章。您不能拥有 Harry & 的文章。里克,因为老板不希望两个或更多作者写同一篇文章。

我们如何在 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.pysyncdb 来执行 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 添加到 Article 对象 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 用于创建一对一关系。

我们可以在上面的 models.py 文件中使用reporter = models.OneToOneField(Reporter),但它在我们的示例中没有用,因为作者无法发布多于一篇文章。

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

我强烈建议尝试使用 OneToOneField 的示例并意识到其中的差异。我非常确定,在这个示例之后,您将完全了解 django OneToOneField 和 django ForeignKey 之间的区别。

The best and the most effective way to learn new things is to see and study real world practical examples. Suppose for a moment that you want to build a blog in django where reporters can write and publish news articles. The owner of the online newspaper wants to allow each of his reporters to publish as many articles as they want, but does not want different reporters to work on the same article. This means that when readers go and read an article they will se only one author in the article.

For example: Article by John, Article by Harry, Article by Rick. You can not have Article by Harry & Rick because the boss does not want two or more authors to work on the same article.

How can we solve this 'problem' with the help of django? The key to the solution of this problem is the django ForeignKey.

The following is the full code which can be used to implement the idea of our boss.

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

Run python manage.py syncdb to execute the sql code and build the tables for your app in your database. Then use python manage.py shell to open a python shell.

Create the Reporter object R1.

In [49]: from thepub.models import Reporter, Article

In [50]: R1 = Reporter(first_name='Rick')

In [51]: R1.save()

Create the Article object A1.

In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)

In [6]: A1.save()

Then use the following piece of code to get the name of the reporter.

In [8]: A1.reporter.first_name
Out[8]: 'Rick'

Now create the Reporter object R2 by running the following python code.

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

In [10]: R2.save()

Now try to add R2 to the Article object A1.

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

It does not work and you will get an AttributeError saying 'Reporter' object has no attribute 'add'.

As you can see an Article object can not be related to more than one Reporter object.

What about R1? Can we attach more than one Article objects to it?

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

This practical example shows us that django ForeignKey is used to define many-to-one relationships.

OneToOneField is used to create one-to-one relationships.

We can use reporter = models.OneToOneField(Reporter) in the above models.py file but it is not going to be useful in our example as an author will not be able to post more than one article.

Each time you want to post a new article you will have to create a new Reporter object. This is time consuming, isn't it?

I highly recommend to try the example with the OneToOneField and realize the difference. I am pretty sure that after this example you will completly know the difference between django OneToOneField and django ForeignKey.

╰つ倒转 2024-11-11 19:16:09

OneToOneField(一对一)在面向对象中实现了组合的概念,而ForeignKey(一对多)则与聚合相关。

OneToOneField (one-to-one) realizes, in object orientation, the notion of composition, while ForeignKey (one-to-many) relates to agregation.

℉絮湮 2024-11-11 19:16:09

此外,OneToOneField 可用作主键以避免键重复。可能没有隐式/显式自动字段

models.AutoField(primary_key=True)

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

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

Also OneToOneField is useful to be used as primary key to avoid key duplication. One may do not have implicit / explicit autofield

models.AutoField(primary_key=True)

but use OneToOneField as primary key instead (imagine UserProfile model for example):

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')
笑梦风尘 2024-11-11 19:16:09

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

我有一个模型,像这样 -

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 字段不允许我这样做。
参考图片

因此,我将模型更改为 -

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 则可以。

I have also been confused with the usage of both the fields.
Let me give an example for understanding their usage, as I have faced the problem recently and realised the usage of both the fields.

I had a model, like this-

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

Now the problem with this was that I can't make multiple objects with the same user,
i.e. a same user will have attendance on multiple days. Hence, multiple objects with same user.

But the OneToOne field didn't let me do that.
Image for reference

So, I changed my model to-

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

Now it works fine and I can mark attendance for a user on multiple days.

So that's where the difference is, OneToOne field will not allow you to make multiple objects with the same user(as an example) but with ForeignKey it is possible.

新雨望断虹 2024-11-11 19:16:09

当您访问 OneToOneField 时,您将获得查询的字段的值。在此示例中,书籍模型的“标题”字段是 OneToOneField:

>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'

当您访问外键时,您将获得相关的模型对象,然后您可以对其执行进一步的查询。在此示例中,同一本书模型的“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 一样进行过滤和切片。属性名称 book_set 是通过将小写模型名称附加到 _set 生成的。

When you access a OneToOneField you get the value of the field you queried. In this example a book model's 'title' field is a OneToOneField:

>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'

When you access a ForeignKey you get the related model object, which you can then preform further queries against. In this example the same book model's 'publisher' field is a ForeignKey (correlating to the Publisher class model definition):

>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'

With ForeignKey fields queries work the other way too, but they're slightly different due to the non-symmetrical nature of the relationship.

>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]

Behind the scenes, book_set is just a QuerySet and can be filtered and sliced like any other QuerySet. The attribute name book_set is generated by appending the lower case model name to _set.

紫罗兰の梦幻 2024-11-11 19:16:09

OneToOneField:如果第二个表与表2相关

table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')

,则将仅包含与表1的pk值相对应的一条记录,即table2_col1将具有等于表的pk的唯一值,

table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')

表2可能包含与表1的pk值相对应的多个记录。

OneToOneField: if second table is related with

table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')

table2 will contains only one record corresponding to table1's pk value, i.e table2_col1 will have unique value equal to pk of table

table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')

table2 may contains more than one record corresponding to table1's pk value.

∞琼窗梦回ˉ 2024-11-11 19:16:09

绘制项目之间关系的最简单方法是用简单的语言理解它们。示例

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

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

The easiest way to draw a relationship between items is by understanding them in plain languages. Example

A user can have many cars but then a car can have just one owner. After establishing this, the foreign key should be used on the item with the many relationship. In this case the car. Meaning you'll include user as a foreign key in cars

And a one on one relationship is quite simple. Say a man and a heart. A man has only one heart and a heart can belong to just one man

北方。的韩爷 2024-11-11 19:16:09

OneToOneField(示例:一辆车有一个车主)
foreignKey(OneToMany)(例如:一家餐厅有很多商品)

OneToOneField (Example: one car has one owner)
ForeignKey(OneToMany) (Example: one restaurant has many items)

旧故 2024-11-11 19:16:09

foreignKey 允许您接收子类(它是另一个类的定义),但 OneToOneFields 不能执行此操作,并且它不能附加到多个变量

ForeignKey allows you receive subclasses is it definition of another class but OneToOneFields cannot do this and it is not attachable to multiple variables

<逆流佳人身旁 2024-11-11 19:16:09

OneToOneField() 无法使用 _setForeignKey()ManyToManyField() 可以。 *您可以看到 我的问题关于它的答案

例如,您有 Person 模型和带有 OneToOneField()PersonDetail 模型,如下所示:

class Person(models.Model):
    name = models.CharField(max_length=20)

class PersonDetail(models.Model):
    person = models.OneToOneField(Person, on_delete=models.CASCADE)
    age = models.IntegerField()
    gender = models.CharField(max_length=20)

然后,您无法访问子模型 PersonDetailPerson 对象的 persondetail_set 如下所示,因为存在错误。 *在 OneToOneField() 的情况下,使用 persondetail 而不是 persondetail_set 来访问子模型 PersonDetail

obj = Person.objects.get(id=1)
print(obj.persondetail_set.get(id=1)) # Error
        # ↑ ↑ ↑ Here ↑ ↑ ↑

现在,您使用 ForeignKey()ManyToManyField() 如下所示:

class PersonDetail(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    # ...
class PersonDetail(models.Model):
    person = models.ManyToManyField(Person)
    # ...

然后,您可以使用 persondetail_set 访问子模型 PersonDetail Person 对象的 code> 如下所示:

obj = Person.objects.get(id=1)
print(obj.persondetail_set.get(id=1)) # PersonDetail object (1)
        # ↑ ↑ ↑ Here ↑ ↑ ↑

OneToOneField() cannot access the child model with _set while ForeignKey() and ManyToManyField() can. *You can see my question and the answer about it.

For example, you have Person model and PersonDetail model with OneToOneField() as shown below:

class Person(models.Model):
    name = models.CharField(max_length=20)

class PersonDetail(models.Model):
    person = models.OneToOneField(Person, on_delete=models.CASCADE)
    age = models.IntegerField()
    gender = models.CharField(max_length=20)

Then, you cannot access the child model PersonDetail with persondetail_set of a Person object as shown below because there is error. *Use persondetail instead of persondetail_set to access the child model PersonDetail in this case of OneToOneField():

obj = Person.objects.get(id=1)
print(obj.persondetail_set.get(id=1)) # Error
        # ↑ ↑ ↑ Here ↑ ↑ ↑

Now, you use ForeignKey() and ManyToManyField() as shown below:

class PersonDetail(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    # ...
class PersonDetail(models.Model):
    person = models.ManyToManyField(Person)
    # ...

Then, you can access the child model PersonDetail with persondetail_set of a Person object as shown below:

obj = Person.objects.get(id=1)
print(obj.persondetail_set.get(id=1)) # PersonDetail object (1)
        # ↑ ↑ ↑ Here ↑ ↑ ↑
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文