Answers:
请注意,OneToOneField(SomeModel)
和之间存在一些差异ForeignKey(SomeModel, unique=True)
。如《 Django权威指南》所述:
一对一
一对一的关系。从概念上讲,这与
ForeignKey
with 相似unique=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>
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
e.car
也可以工作?
ForeignKey
with unique=True
而不是a OneToOneField
?我在其他问题中看到Django甚至警告说,OneToOneField
通常最好的服务是自己的利益。反向QuerySet
永远不会有多个元素,对吗?
ForeignKey是一对多的,因此Car对象可能有多个Wheels,每个Wheel都具有与其所属的Car的ForeignKey。OneToOneField就像是Engine,其中Car对象可以只有一个并且只有一个。
学习新事物的最好,最有效的方法是查看和研究现实世界中的实例。假设您想在django中建立一个博客,让记者可以撰写和发布新闻文章。在线报纸的所有者希望允许他的每个记者根据需要发布任意数量的文章,但不希望其他记者从事同一篇文章。这意味着当读者去阅读一篇文章时,他们只会在文章中找到一位作者。
例如:John的文章,Harry的文章,Rick的文章。您不能拥有Harry&Rick的Article,因为老板不希望两个或多个作者撰写同一篇文章。
我们如何在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。
创建报告程序对象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添加到商品对象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
用于创建一对一关系。
我们可以reporter = models.OneToOneField(Reporter)
在上面的models.py文件中使用它,但是在我们的示例中该文件将无用,因为作者将不能发表多篇文章。
每次您要发布新文章时,都必须创建一个新的Reporter对象。这很费时间,不是吗?
我强烈建议您尝试使用的示例,OneToOneField
并体会不同之处。我很确定,在此示例之后,您将完全了解django OneToOneField
和django 之间的区别ForeignKey
。
也 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时,您将获得相关的模型对象,然后可以对其执行进一步的查询。在此示例中,同一本书模型的“ 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一样进行过滤和切片。通过将小写的模型名称附加到_set来生成属性名称book_set。
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值相对应的记录。