6 ответов:
будьте осторожны, чтобы понять, что есть некоторые различия между
OneToOneField(SomeModel)иForeignKey(SomeModel, unique=True). Как указано в окончательное руководство по Django:OneToOneField
один-к-одному отношения. Концептуально это похоже на
ForeignKeyСunique=True, но "обратная" сторона отношения будет непосредственно возвращать один объект.в отличие от
OneToOneField"обратная" отношение, аForeignKey"обратное" отношение возвращает aQuerySet.пример
например, если у нас есть следующие две модели (полный код модели ниже):
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
иностранный ключ предназначен для одного ко многим, поэтому объект автомобиля может иметь много колес, каждое колесо имеет иностранный ключ к автомобилю, которому оно принадлежит. OneToOneField будет похож на двигатель, где объект автомобиля может иметь один и только один.
лучший и самый эффективный способ узнать что-то новое-это увидеть и изучить реальные практические примеры. Предположим на мгновение, что вы хотите построить блог в 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.titleRun
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 в статью объект А1.
In [13]: A1.reporter.add(R2)это не работает, и вы получите AttributeError говоря "репортер" объект не имеет атрибута "добавить".
как вы можете видеть, объект статьи не может быть связан с более чем одним объектом репортера.
как насчет 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используется для определения отношений "многие к одному".это чтобы создать отношения один-к-одному.
можно использовать
reporter = models.OneToOneField(Reporter)в вышеуказанном models.py но это не будет полезно в нашем примере, поскольку автор не сможет опубликовать более одной статьи.каждый раз, когда вы хотите опубликовать новую статью, вам нужно будет создать новый объект Reporter. Это отнимает много времени, не так ли?
я настоятельно рекомендую попробовать пример с
OneToOneFieldи поймете разницу. Я уверен, что после этого пример вы будете полностью знать разницу между djangoOneToOneFieldи DjangoForeignKey.
OneToOneField (one-to-one) реализует в объектной ориентации понятие композиции, в то время как ForeignKey (one-to-many) относится к агрегации.
при доступе к OneToOneField вы получаете значение поля, которое вы запросили. В этом примере поле 'title' модели книги является OneToOneField:
>>> from mysite.books.models import Book >>> b = Book.objects.get(id=50) >>> b.title u'The Django Book'при доступе к внешнему ключу вы получаете Связанный объект модели,который затем можно предварительно сформировать дальнейшие запросы. В этом примере поле 'publisher' той же модели книги является внешним ключом (коррелирующим с определением модели класса 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-это просто набор запросов, который можно фильтровать и нарезать, как и любой другой набор запросов. Имя атрибута book_set создается путем добавления имени модели в нижнем регистре к _set.
и
OneToOneFieldполезно использовать в качестве первичного ключа, чтобы избежать дублирования ключей. Можно не иметь неявного / явного autofieldmodels.AutoField(primary_key=True)но использовать
OneToOneFieldкак первичный ключ вместо этого (представьте себеUserProfileмодель например):user = models.OneToOneField( User, null=False, primary_key=True, verbose_name='Member profile')
Comments