Respuestas:
Tenga cuidado de darse cuenta de que hay algunas diferencias entre OneToOneField(SomeModel)
y ForeignKey(SomeModel, unique=True)
. Como se indica en la Guía definitiva de Django :
OneToOneField
Una relación uno a uno. Conceptualmente, esto es similar a un
ForeignKey
conunique=True
, pero el lado "inverso" de la relación devolverá directamente un solo objeto.
En contraste con la relación OneToOneField
"inversa", una relación ForeignKey
"inversa" devuelve a QuerySet
.
Por ejemplo, si tenemos los dos modelos siguientes (código de modelo completo a continuación):
Car
usos del modelo OneToOneField(Engine)
Car2
usos del modelo ForeignKey(Engine2, unique=True)
Desde adentro python manage.py shell
ejecute lo siguiente:
OneToOneField
Ejemplo>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>
ForeignKey
con el unique=True
ejemplo>>> 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
también funciona?
ForeignKey
con en unique=True
lugar de un OneToOneField
? Veo en otras preguntas que Django incluso advierte que OneToOneField
los intereses de un mejor servicio suelen ser los mejores. Lo contrario QuerySet
nunca tendrá más de un elemento, ¿verdad?
Una ForeignKey es para uno a muchos, por lo que un objeto Car puede tener muchas Ruedas, cada Rueda tiene una ForeignKey para el Car al que pertenece. Un OneToOneField sería como un motor, donde un objeto Car puede tener uno y solo uno.
La mejor y más efectiva forma de aprender cosas nuevas es ver y estudiar ejemplos prácticos del mundo real. Supongamos por un momento que desea crear un blog en django donde los reporteros puedan escribir y publicar artículos de noticias. El propietario del periódico en línea quiere permitir que cada uno de sus reporteros publique tantos artículos como quiera, pero no quiere que diferentes reporteros trabajen en el mismo artículo. Esto significa que cuando los lectores van y leen un artículo, verán solo un autor en el artículo.
Por ejemplo: Artículo de John, Artículo de Harry, Artículo de Rick. No puede tener el artículo de Harry & Rick porque el jefe no quiere que dos o más autores trabajen en el mismo artículo.
¿Cómo podemos resolver este 'problema' con la ayuda de django? La clave para la solución de este problema es el django.ForeignKey
.
El siguiente es el código completo que se puede utilizar para implementar la idea de nuestro jefe.
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
Ejecute python manage.py syncdb
para ejecutar el código sql y compile las tablas para su aplicación en su base de datos. Luego, use python manage.py shell
para abrir un shell de python.
Cree el objeto Reporter R1.
In [49]: from thepub.models import Reporter, Article
In [50]: R1 = Reporter(first_name='Rick')
In [51]: R1.save()
Cree el objeto Artículo A1.
In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)
In [6]: A1.save()
Luego use el siguiente código para obtener el nombre del reportero.
In [8]: A1.reporter.first_name
Out[8]: 'Rick'
Ahora cree el objeto Reporter R2 ejecutando el siguiente código de Python.
In [9]: R2 = Reporter.objects.create(first_name='Harry')
In [10]: R2.save()
Ahora intente agregar R2 al objeto Artículo A1.
In [13]: A1.reporter.add(R2)
No funciona y obtendrá un AttributeError que dice que el objeto 'Reportero' no tiene el atributo 'agregar'.
Como puede ver, un objeto Artículo no puede estar relacionado con más de un objeto Reportero.
¿Qué hay de R1? ¿Podemos adjuntarle más de un objeto de artículo?
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>]
Este ejemplo práctico nos muestra que django ForeignKey
se usa para definir relaciones de muchos a uno.
OneToOneField
se usa para crear relaciones uno a uno.
Nosotros podemos usar reporter = models.OneToOneField(Reporter)
en el archivo models.py anterior, pero no será útil en nuestro ejemplo, ya que un autor no podrá publicar más de un artículo.
Cada vez que desee publicar un nuevo artículo, tendrá que crear un nuevo objeto Reporter. Esto lleva mucho tiempo, ¿no?
Recomiendo probar el ejemplo con el OneToOneField
y darse cuenta de la diferencia. Estoy bastante seguro de que después de este ejemplo sabrás por completo la diferencia entre django OneToOneField
y django ForeignKey
.
OneToOneField (uno a uno) se da cuenta, en orientación de objeto, la noción de composición, mientras ForeignKey (uno a muchos) se relaciona con la agregación.
Patient
y Organ
. Patient
puede tener muchos Organ
s, pero un solo Organ
puede pertenecer a uno Patient
. Cuando Patient
se elimina, todos los Organ
correos electrónicos también se eliminan. No pueden existir sin un Patient
.
También OneToOneField
es útil para usarse como clave principal para evitar la duplicación de claves. Uno puede no tener autocampo implícito / explícito
models.AutoField(primary_key=True)
pero use OneToOneField
como clave primaria en su lugar (imagine el UserProfile
modelo, por ejemplo):
user = models.OneToOneField(
User, null=False, primary_key=True, verbose_name='Member profile')
Cuando accede a OneToOneField obtiene el valor del campo que ha consultado. En este ejemplo, el campo 'título' de un modelo de libro es OneToOneField:
>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'
Cuando accede a una ForeignKey, obtiene el objeto de modelo relacionado, que luego puede realizar más consultas. En este ejemplo, el campo 'editor' del mismo modelo de libro es una ForeignKey (correlacionada con la definición del modelo de clase Publisher):
>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'
Con los campos ForeignKey, las consultas también funcionan a la inversa, pero son ligeramente diferentes debido a la naturaleza no simétrica de la relación.
>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]
Detrás de escena, book_set es solo un QuerySet y se puede filtrar y dividir como cualquier otro QuerySet. El nombre del atributo book_set se genera agregando el nombre del modelo en minúsculas a _set.
OneToOneField: si la segunda tabla está relacionada con
table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')
table2 contendrá solo un registro correspondiente al valor pk de table1, es decir, table2_col1 tendrá un valor único igual a pk de table
table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')
table2 puede contener más de un registro correspondiente al valor pk de table1.