Antworten:
Achten Sie darauf, dass es einige Unterschiede zwischen OneToOneField(SomeModel)
und gibt ForeignKey(SomeModel, unique=True)
. Wie im endgültigen Leitfaden für Django angegeben :
OneToOneField
Eine Eins-zu-Eins-Beziehung. Konzeptionell ähnelt dies einem
ForeignKey
withunique=True
, aber die "umgekehrte" Seite der Beziehung gibt direkt ein einzelnes Objekt zurück.
Im Gegensatz zur OneToOneField
"umgekehrten" Beziehung gibt eine ForeignKey
"umgekehrte" Beziehung a zurück QuerySet
.
Zum Beispiel, wenn wir die folgenden zwei Modelle haben (vollständiger Modellcode unten):
Car
Modell verwendet OneToOneField(Engine)
Car2
Modell verwendet ForeignKey(Engine2, unique=True)
python manage.py shell
Führen Sie von innen Folgendes aus:
OneToOneField
Beispiel>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>
ForeignKey
mit unique=True
Beispiel>>> 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
e.car
funktioniert , wenn der Fremdschlüssel eindeutig und nicht null ist ?
ForeignKey
mit unique=True
anstatt eines verwenden wollen OneToOneField
? Ich sehe in anderen Fragen, dass Django sogar warnt, dass OneToOneField
die Interessen eines normalerweise am besten dienen. Das Gegenteil QuerySet
wird niemals mehr als ein Element haben, oder?
Ein ForeignKey ist für eins zu viele, daher kann ein Autoobjekt viele Räder haben, wobei jedes Rad einen ForeignKey für das Auto hat, zu dem es gehört. Ein OneToOneField wäre wie ein Motor, bei dem ein Autoobjekt nur einen haben kann.
Der beste und effektivste Weg, neue Dinge zu lernen, besteht darin, praktische Beispiele aus der Praxis zu sehen und zu studieren. Angenommen, Sie möchten für einen Moment ein Blog in Django erstellen, in dem Reporter Nachrichtenartikel schreiben und veröffentlichen können. Der Inhaber der Online-Zeitung möchte jedem seiner Reporter erlauben, so viele Artikel zu veröffentlichen, wie er möchte, möchte jedoch nicht, dass verschiedene Reporter an demselben Artikel arbeiten. Dies bedeutet, dass Leser, die einen Artikel lesen, nur einen Autor im Artikel sehen.
Zum Beispiel: Artikel von John, Artikel von Harry, Artikel von Rick. Sie können keinen Artikel von Harry & Rick haben, da der Chef nicht möchte, dass zwei oder mehr Autoren an demselben Artikel arbeiten.
Wie können wir dieses "Problem" mit Hilfe von Django lösen? Der Schlüssel zur Lösung dieses Problems ist der Django ForeignKey
.
Das Folgende ist der vollständige Code, mit dem die Idee unseres Chefs umgesetzt werden kann.
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
Führen Sie python manage.py syncdb
diese Option aus, um den SQL-Code auszuführen und die Tabellen für Ihre App in Ihrer Datenbank zu erstellen. Verwenden Sie dann python manage.py shell
, um eine Python-Shell zu öffnen.
Erstellen Sie das Reporter-Objekt R1.
In [49]: from thepub.models import Reporter, Article
In [50]: R1 = Reporter(first_name='Rick')
In [51]: R1.save()
Erstellen Sie das Artikelobjekt A1.
In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)
In [6]: A1.save()
Verwenden Sie dann den folgenden Code, um den Namen des Reporters abzurufen.
In [8]: A1.reporter.first_name
Out[8]: 'Rick'
Erstellen Sie nun das Reporter-Objekt R2, indem Sie den folgenden Python-Code ausführen.
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
Versuchen Sie nun, R2 zum Artikelobjekt A1 hinzuzufügen.
In [13]: A1.reporter.add(R2)
Es funktioniert nicht und Sie erhalten einen AttributeError, der besagt, dass das Objekt 'Reporter' kein Attribut 'add' hat.
Wie Sie sehen, kann ein Artikelobjekt nicht mit mehr als einem Reporterobjekt verknüpft werden.
Was ist mit R1? Können wir mehr als ein Artikelobjekt daran anhängen?
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>]
Dieses praktische Beispiel zeigt uns, dass Django ForeignKey
verwendet wird, um viele-zu-eins-Beziehungen zu definieren.
OneToOneField
wird verwendet, um Eins-zu-Eins-Beziehungen zu erstellen.
Wir können reporter = models.OneToOneField(Reporter)
die obige Datei models.py verwenden, sie ist jedoch in unserem Beispiel nicht hilfreich, da ein Autor nicht mehr als einen Artikel veröffentlichen kann.
Jedes Mal, wenn Sie einen neuen Artikel veröffentlichen möchten, müssen Sie ein neues Reporter-Objekt erstellen. Das ist zeitaufwändig, nicht wahr?
Ich empfehle dringend, das Beispiel mit dem zu versuchen OneToOneField
und den Unterschied zu erkennen. Ich bin mir ziemlich sicher, dass Sie nach diesem Beispiel den Unterschied zwischen Django OneToOneField
und Django vollständig kennen ForeignKey
.
OneToOneField (Eins-zu-Eins) verwirklicht in der Objektorientierung den Begriff der Komposition, während ForeignKey (Eins-zu-Viele) sich auf Agregation bezieht.
Patient
und Organ
. Patient
kann viele Organ
s haben, aber eine Organ
kann nur zu einem gehören Patient
. Wenn Patient
gelöscht wird, werden auch alle Organ
s gelöscht. Sie können nicht ohne existieren Patient
.
Es OneToOneField
ist auch nützlich, als Primärschlüssel verwendet zu werden, um das Duplizieren von Schlüsseln zu vermeiden. Man kann kein implizites / explizites Autofeld haben
models.AutoField(primary_key=True)
Verwenden Sie OneToOneField
stattdessen den Primärschlüssel (stellen Sie sich beispielsweise ein UserProfile
Modell vor):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
Wenn Sie auf ein OneToOneField zugreifen, erhalten Sie den Wert des abgefragten Feldes. In diesem Beispiel ist das Titelfeld eines Buchmodells ein OneToOneField:
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
Wenn Sie auf einen ForeignKey zugreifen, erhalten Sie das zugehörige Modellobjekt, für das Sie weitere Abfragen durchführen können. In diesem Beispiel ist das Feld "Publisher" des gleichen Buchmodells ein ForeignKey (korreliert mit der Definition des Publisher-Klassenmodells):
>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'
Bei ForeignKey-Feldern funktionieren Abfragen auch umgekehrt, unterscheiden sich jedoch aufgrund der nicht symmetrischen Natur der Beziehung geringfügig.
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
Hinter den Kulissen ist book_set nur ein QuerySet und kann wie jedes andere QuerySet gefiltert und in Scheiben geschnitten werden. Der Attributname book_set wird generiert, indem der Modellname in Kleinbuchstaben an _set angehängt wird.
OneToOneField: Wenn die zweite Tabelle mit verwandt ist
table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')
Tabelle2 enthält nur einen Datensatz, der dem pk-Wert von Tabelle1 entspricht, dh table2_col1 hat einen eindeutigen Wert, der pk der Tabelle entspricht
table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')
Tabelle2 kann mehr als einen Datensatz enthalten, der dem pk-Wert von Tabelle1 entspricht.