В чем разница между django OneToOneField и ForeignKey?
OneToOneField (взаимно-однозначный) реализует в объектной ориентации понятие композиции, в то время как ForeignKey (один-ко-многим) относится к агрегированию.
A ForeignKey для одного-ко-многим, поэтому объект Car может иметь много колес, каждое колесо имеет ForeignKey для автомобиля, к которому он принадлежит. OneToOneField будет похож на движок, в котором объект Car может иметь один и только один.
Лучший и самый эффективный способ узнать новое - увидеть и изучить реальные практические примеры. Предположим на мгновение, что вы хотите создать блог в django, где журналисты могут писать и публиковать новостные статьи. Владелец интернет-газеты хочет разрешить каждому из своих репортеров публиковать как можно больше статей, но не хочет, чтобы разные журналисты работали над одной и той же статьей. Это означает, что когда читатели идут и читают статью, в статье будет только один автор.
Например: Статья Джона, статья Гарри, статья Рика. Вы не можете иметь статью от Harry & amp; Рик, потому что босс не хочет, чтобы два или более автора работали над одной и той же статьей.
Как мы можем решить эту «проблему» с помощью 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.
Создайте объект 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'
Теперь создайте объект Reporter R2, запустив следующий код python.
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
Теперь попробуйте добавить R2 в объект статьи A1.
In [13]: A1.reporter.add(R2)
Это не работает, и вы получите AttributeError, говорящий, что объект «Репортер» не имеет атрибута «Добавить».
Как вы может видеть, что объект Article не может быть связан с более чем одним объектом Репортера.
Что относительно 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 используется для создания отношений один к одному.
Мы можем использовать reporter = models.OneToOneField(Reporter) в вышеуказанном файле models.py, но он не будет полезен в наш пример как автора не сможет опубликовать более одной статьи.
Каждый раз, когда вы хотите опубликовать новую статью, вам придется создать новый объект Reporter. Это много времени, не так ли?
Я настоятельно рекомендую попробовать пример с OneToOneField и понять разницу. Я уверен, что после этого примера вы полностью узнаете разницу между django OneToOneField и django ForeignKey.
Также OneToOneField полезно использовать в качестве первичного ключа, чтобы избежать дублирования ключей. Можно использовать неявный / явный autofield
models.AutoField(primary_key=True)
, но вместо этого использовать OneToOneField в качестве первичного ключа (например, модель UserProfile):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
Когда вы получаете доступ к OneToOneField, вы получаете значение поля, которое вы запрашивали. В этом примере поле «title» в книжной модели - 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.