Quelle est la différence entre django OneToOneField et ForeignKey?
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
avecunique=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):
-
Car
modèle utiliseOneToOneField(Engine)
-
Car2
modèle utiliseForeignKey(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
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.
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
.
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.
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.
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')