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
con unique=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
.
Ejemplo
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>]
Código modelo
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 enunique=True
lugar de unOneToOneField
? Veo en otras preguntas que Django incluso advierte queOneToOneField
los intereses de un mejor servicio suelen ser los mejores. Lo contrarioQuerySet
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.
fuente
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.
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, usepython manage.py shell
para abrir un shell de python.Cree el objeto Reporter R1.
Cree el objeto Artículo A1.
Luego use el siguiente código para obtener el nombre del reportero.
Ahora cree el objeto Reporter R2 ejecutando el siguiente código de Python.
Ahora intente agregar R2 al objeto Artículo A1.
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?
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 djangoOneToOneField
y djangoForeignKey
.fuente
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.
fuente
Patient
yOrgan
.Patient
puede tener muchosOrgan
s, pero un soloOrgan
puede pertenecer a unoPatient
. CuandoPatient
se elimina, todos losOrgan
correos electrónicos también se eliminan. No pueden existir sin unPatient
.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ícitopero use
OneToOneField
como clave primaria en su lugar (imagine elUserProfile
modelo, por ejemplo):fuente
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:
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):
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.
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.
fuente
OneToOneField: si la segunda tabla está relacionada con
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 puede contener más de un registro correspondiente al valor pk de table1.
fuente
ForeignKey le permite recibir subclases si es una definición de otra clase, pero OneToOneFields no puede hacer esto y no se puede adjuntar a múltiples variables
fuente