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
ForeignKeyconunique=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 shellejecute 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>
ForeignKeycon el unique=Trueejemplo>>> 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.cartambién funciona?
ForeignKeycon en unique=Truelugar de un OneToOneField? Veo en otras preguntas que Django incluso advierte que OneToOneFieldlos intereses de un mejor servicio suelen ser los mejores. Lo contrario QuerySetnunca 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 syncdbpara ejecutar el código sql y compile las tablas para su aplicación en su base de datos. Luego, use python manage.py shellpara 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 ForeignKeyse 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 OneToOneFieldy darse cuenta de la diferencia. Estoy bastante seguro de que después de este ejemplo sabrás por completo la diferencia entre django OneToOneFieldy 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.
Patienty Organ. Patientpuede tener muchos Organs, pero un solo Organpuede pertenecer a uno Patient. Cuando Patientse elimina, todos los Organcorreos electrónicos también se eliminan. No pueden existir sin un Patient.
También OneToOneFieldes ú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 OneToOneFieldcomo clave primaria en su lugar (imagine el UserProfilemodelo, 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.