В чем разница между django OneToOneField и ForeignKey?



в чем разница между django OneToOneField и ForeignKey?

666   6  

6 ответов:

будьте осторожны, чтобы понять, что есть некоторые различия между OneToOneField(SomeModel) и ForeignKey(SomeModel, unique=True). Как указано в окончательное руководство по Django:

OneToOneField

один-к-одному отношения. Концептуально это похоже на ForeignKey С unique=True, но "обратная" сторона отношения будет непосредственно возвращать один объект.

в отличие от OneToOneField "обратная" отношение, а ForeignKey "обратное" отношение возвращает a 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>

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.title

Run 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 и поймете разницу. Я уверен, что после этого пример вы будете полностью знать разницу между django OneToOneField и Django ForeignKey.

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 полезно использовать в качестве первичного ключа, чтобы избежать дублирования ключей. Можно не иметь неявного / явного autofield

models.AutoField(primary_key=True)

но использовать OneToOneField как первичный ключ вместо этого (представьте себе UserProfile модель например):

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

Comments

    Ничего не найдено.