Quelle est la différence entre django OneToOneField et ForeignKey?

Quelle est la différence entre django OneToOneField et ForeignKey?

286
demandé sur mrehan 2011-05-03 17:54:18

6 réponses

attention, il y a des différences entre OneToOneField(SomeModel) et ForeignKey(SomeModel, unique=True) . Comme indiqué dans le Guide définitif de Django :

OneToOneField

one-to-one relation. Sur le plan conceptuel, cela est similaire à un ForeignKey avec unique=True , mais le" revers " de la relation retournera directement un seul objet.

à la différence de la relation OneToOneField " reverse", une relation ForeignKey " reverse "retourne une relation QuerySet .

exemple

par exemple, si nous avons les deux modèles suivants (code de modèle complet ci-dessous):

  1. Car modèle utilise OneToOneField(Engine)
  2. Car2 modèle utilise ForeignKey(Engine2, unique=True)

de l'intérieur de python manage.py shell exécuter ce qui suit:

OneToOneField exemple

>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>

ForeignKey avec unique=True exemple

>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]

Code De Modèle

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
387
répondu Matthew Rankin 2018-06-10 08:06:27

une clé étrangère est pour un-à-plusieurs, donc un objet de voiture pourrait avoir plusieurs roues, chaque roue ayant une clé étrangère à la voiture à laquelle il appartient. Un OneToOneField serait comme un moteur, où un objet de voiture peut en avoir un et un seul.

82
répondu Dan Breen 2011-05-03 13:58:22

la meilleure et la plus efficace façon d'apprendre de nouvelles choses est de voir et d'étudier des exemples pratiques du monde réel. Supposons un instant que vous vouliez créer un blog à django où les journalistes pourraient écrire et publier des articles. Le propriétaire du journal en ligne veut permettre à chacun de ses journalistes de publier autant d'articles qu'il le souhaite, mais ne veut pas que des journalistes différents travaillent sur le même article. Cela signifie que lorsque les lecteurs vont et lisent un article, ils ne verront qu'un seul auteur dans l'article.

par exemple: Article de John, article de Harry, Article de Rick. Vous ne pouvez pas avoir L'Article de Harry & Rick parce que le patron ne veut pas que deux ou plusieurs auteurs travaillent sur le même article.

comment résoudre ce "problème" avec l'aide de django? La clé de la solution de ce problème est le django ForeignKey .

voici le code complet qui peut être utilisé pour mettre en œuvre l'idée de notre patron.

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

exécutez python manage.py syncdb pour exécuter le code sql et construire les tables pour votre application dans votre base de données. Ensuite, utilisez python manage.py shell pour ouvrir un shell python.

créer l'objet Reporter R1.

In [49]: from thepub.models import Reporter, Article

In [50]: R1 = Reporter(first_name='Rick')

In [51]: R1.save()

créer l'article objet A1.

In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)

In [6]: A1.save()

puis utilisez le morceau de code suivant pour obtenir le nom du reporter.

In [8]: A1.reporter.first_name
Out[8]: 'Rick'

maintenant créer le Journaliste objet R2 en exécutant le code python suivant.

In [9]: R2 = Reporter.objects.create(first_name='Harry')

In [10]: R2.save()

maintenant, essayez D'ajouter R2 à l'objet de L'Article A1.

In [13]: A1.reporter.add(R2)

cela ne fonctionne pas et vous obtiendrez un AttributeError disant 'Reporter' objet n'a pas d'attribut 'add'.

comme vous pouvez le voir, un objet Article ne peut être relié à plus d'un objet Reporter.

et R1? Pouvons-nous attacher plus d'un objet à il?

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>]

cet exemple pratique nous montre que django ForeignKey est utilisé pour définir les relations entre plusieurs personnes.

OneToOneField est utilisé pour créer un-à-un les relations.

Nous pouvons utiliser reporter = models.OneToOneField(Reporter) ci-dessus models.py fichier mais il ne va pas être utile dans notre exemple, qu'un auteur ne sera pas en mesure de poster plus d'un article.

Chaque fois que vous voulez poster un nouveau article vous devrez créer un nouvel objet Reporter. Cela prend du temps, n'est-ce pas?

je recommande fortement d'essayer l'exemple avec le OneToOneField et de réaliser la différence. Je suis assez sûr qu'après cet exemple vous connaîtrez parfaitement la différence entre django OneToOneField et django ForeignKey .

18
répondu jetbird13 2014-11-14 19:29:58

OneToOneField (one-to-one) réalise, dans l'orientation de l'objet, la notion de composition, tandis que ForeignKey (one-to-many) se rapporte à l'agrégation.

10
répondu andrers52 2012-04-27 21:42:52

lorsque vous accédez à un champ OneToOneField, vous obtenez la valeur du champ que vous avez interrogé. Dans cet exemple, le champ "Titre" d'un modèle de livre est un champ OneToOneField:

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

lorsque vous accédez à une clé étrangère, vous obtenez l'objet model correspondant, contre lequel vous pouvez préformer d'autres requêtes. Dans cet exemple, le champ "publisher" du même modèle de livre est une clé étrangère (corrélée à la définition du modèle de classe Publisher):

>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'

Avec ForeignKey les requêtes fields fonctionnent également dans l'autre sens, mais elles sont légèrement différentes en raison de la nature non symétrique de la relation.

>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]

dans les coulisses, book_set est juste un QuerySet et peut être filtré et tranché comme n'importe quel autre QuerySet. L'attribut nom book_set est généré en ajoutant le nom de modèle minuscule à _set.

1
répondu Yup. 2014-02-12 18:59:13

aussi OneToOneField est utile pour être utilisé comme clé primaire pour éviter la duplication des clés. On peut ne pas avoir implicite / explicite autofield

models.AutoField(primary_key=True)

mais utilisez OneToOneField comme clé primaire à la place (imaginez UserProfile modèle par exemple):

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')
0
répondu Dmitriy Sintsov 2016-03-26 16:58:44