2011-05-03 77 views

回答

359

小心認識到OneToOneField(SomeModel)ForeignKey(SomeModel, unique=True)之間有一些差異。正如The Definitive Guide to Django指出:

OneToOneField

一個一對一的關係。從概念上講,這與與unique=True類似,但關係的「反向」側將直接返回單個對象。

與此相反的OneToOneField「反向」的關係,一個ForeignKey「反向」關係返回QuerySet

例如,如果我們有以下兩個模型(下面完整模型代碼):

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

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) 

    def __unicode__(self): 
     return self.name 
+4

@MarkPNeyer:據我所知,OneToOne字段就是:一對一。它不一定要上。見[**這個例子**](https://docs.djangoproject.com/en/dev/topics/db/examples/one_to_one/):一個地方不一定是餐廳。 – osa 2013-12-04 20:36:13

+6

這個答案說「有一些差異」,然後命名一個區別。有其他人嗎? – 2014-08-06 08:35:30

+2

我想和克里斯一樣。它僅僅是語法糖,數據訪問方式是否存在一些根本性差異,導致性能差異? – Carlos 2014-08-10 13:16:02

76

ForeignKey是一對多的,所以一個Car對象可能有很多個車輪,每個車輪都有一個到它所屬的Car的ForeignKey。 OneToOneField就像一個引擎,一個Car對象可以只有一個。

+2

謝謝你,劑量OneToOneField(someModel)平均ForeignKey的(SomeModel,獨特= TRUE)? – redice 2011-05-03 14:13:21

+3

是的:'OneToOneField本質上與ForeignKey相同,除了它總是攜帶一個「唯一」約束,反向關係總是返回指向的對象(因爲只會有一個),而不是返回一個列表。' – 2011-05-03 14:18:05

+1

幾款具有相同發動機的汽車呢? – 2013-12-04 23:04:01

9

OneToOneField(一到一個)實現,在面向對象,組合物的概念,而ForeignKey(一對多)涉及聚合。

1

當您訪問OneToOneField時,您將獲得您查詢的字段的值。在這個例子中一本書模型的「標題」字段是一個OneToOneField:

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

當你訪問一個ForeignKey你會得到相關的模型對象,然後你就可以對瓶坯進一步查詢。在這個例子中,同一本書型號的「出版商」字段是一個ForeignKey(關聯到發佈服務器類模型定義):

>>> 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,可以過濾和切片像任何其他查詢集。屬性名稱book_set通過將小寫模型名稱附加到_set來生成。

16

學習新事物最好的和最有效的方法是看到和研究現實世界的實例。假設你想在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呢?我們可以附加多個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之間的區別。

0

另外OneToOneField可用作主鍵來避免密鑰重複。人們可能不具有隱性/明確的自動字段

models.AutoField(primary_key=True) 

但使用OneToOneField作爲主鍵,而不是(想象一下,例如UserProfile模型):

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