red*_*ice 353 django django-models
django OneToOneField和ForeignKey有什么区别?
Mat*_*kin 457
小心地意识到OneToOneField(SomeModel)和之间存在一些差异ForeignKey(SomeModel, unique=True).正如Django权威指南中所述:
OneToOneField
一对一的关系.从概念上讲,这类似于
ForeignKeywithunique=True,但关系的"反向"方面将直接返回单个对象.
与OneToOneField"反向"关系相反,ForeignKey"反向"关系返回a 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>
Run Code Online (Sandbox Code Playgroud)
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>]
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
Dan*_*een 107
ForeignKey用于一对多,因此Car对象可能有许多Wheels,每个Wheel对其所属的Car具有ForeignKey.OneToOneField就像一个引擎,其中Car对象可以只有一个.
jet*_*d13 35
学习新事物的最佳和最有效的方法是查看和研究现实世界的实际例子.假设你想在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
Run Code Online (Sandbox Code Playgroud)
运行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()
Run Code Online (Sandbox Code Playgroud)
创建Article对象A1.
In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)
In [6]: A1.save()
Run Code Online (Sandbox Code Playgroud)
然后使用以下代码获取报告者的名称.
In [8]: A1.reporter.first_name
Out[8]: 'Rick'
Run Code Online (Sandbox Code Playgroud)
现在通过运行以下python代码创建Reporter对象R2.
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
Run Code Online (Sandbox Code Playgroud)
现在尝试将R2添加到Article对象A1.
In [13]: A1.reporter.add(R2)
Run Code Online (Sandbox Code Playgroud)
它不起作用,你会得到一个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>]
Run Code Online (Sandbox Code Playgroud)
这个实际例子向我们展示了django ForeignKey用于定义多对一关系.
OneToOneField 用于创建一对一的关系.
我们可以reporter = models.OneToOneField(Reporter)在上面的models.py文件中使用它,但在我们的例子中它不会有用,因为作者将无法发布多篇文章.
每次要发布新文章时,都必须创建一个新的Reporter对象.这很耗时,不是吗?
我强烈建议尝试这个例子OneToOneField并实现差异.我很确定在这个例子之后你将完全知道django OneToOneField和django 之间的区别ForeignKey.
and*_*s52 12
OneToOneField(一对一)以面向对象的方式实现组合的概念,而ForeignKey(一对多)则与聚合有关.
OneToOneField用作主键以避免重复键也很有用。一个可能没有隐式/显式自动字段
models.AutoField(primary_key=True)
Run Code Online (Sandbox Code Playgroud)
但OneToOneField改为用作主键(UserProfile例如想象模型):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
Run Code Online (Sandbox Code Playgroud)
小智 6
我也对这两个字段的用法感到困惑。让我举一个例子来理解它们的用法,因为我最近遇到了这个问题并意识到这两个字段的用法。
我有一个模型,像这样-
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
Run Code Online (Sandbox Code Playgroud)
现在的问题是我无法使用同一用户创建多个对象,即同一用户将在多天内出勤。因此,多个对象具有同一用户。
但 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
Run Code Online (Sandbox Code Playgroud)
现在它工作正常,我可以在多天内标记用户的出勤情况。
这就是区别所在,OneToOne 字段不允许您使用同一用户创建多个对象(作为示例),但使用foreignkey 则可以。
当您访问 OneToOneField 时,您将获得您查询的字段的值。在此示例中,书籍模型的“标题”字段是 OneToOneField:
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
Run Code Online (Sandbox Code Playgroud)
当您访问 ForeignKey 时,您将获得相关的模型对象,然后您可以对其进行进一步的查询。在这个例子中,同一本书模型的 'publisher' 字段是一个外键(与 Publisher 类模型定义相关):
>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'
Run Code Online (Sandbox Code Playgroud)
使用 ForeignKey 字段查询也可以以另一种方式工作,但由于关系的非对称性质,它们略有不同。
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
Run Code Online (Sandbox Code Playgroud)
在幕后,book_set 只是一个 QuerySet,可以像任何其他 QuerySet 一样进行过滤和切片。属性名称 book_set 是通过将小写模型名称附加到 _set 来生成的。
| 归档时间: |
|
| 查看次数: |
99612 次 |
| 最近记录: |