2012-03-21 9 views
10

Supongamos que tenemos los siguientes modelos.Django OneToOneField: ¿en qué modelo debería ponerlo?

class A(Model): pass 
class B(Model): pass 

entonces no hay diferencia entre:

En el modelo A: b = OneToOneField(B, related_name=A.__name__)

y

en el modelo B: a = OneToOneField(A, related_name=B.__name__)

Entonces, ¿qué preguntas le debería hacer a mi mismo para decidir si poner OTO en un modelo u otro. Me refiero a has-a, is-a y demás.

Respuesta

1

Creo que en el caso de un campo OneToOne, la respuesta correcta es que no importa, solo depende del modelo con el que tiene más sentido relacionarse con el otro.

+0

Bueno, esa es la pregunta.¿Cómo averiguo qué tiene más sentido? A veces no hay diferencia y ambas maneras son igualmente posibles. – aemdy

+0

En casos como este, depende completamente de usted. No creo que haya una respuesta definitiva. – Brandon

7

OneToOneField s son realmente sólo para dos propósitos: 1) herencia (Django usa estos para su puesta en práctica del MTI) o 2) la extensión de un modelo no editable (como la creación de un UserProfile para User).

En esos dos escenarios, es obvio qué modelo continúa el OneToOneField. En el caso de la herencia, se aplica al niño. En el caso de la extensión, sigue el único modelo al que tiene acceso.

Con muy pocas excepciones, cualquier otro uso de uno-a-uno solo debería fusionarse en un solo modelo.

+0

Gran respuesta Chris. – Brandon

+0

¿Qué pasa con el bloqueo de la mesa? Si tuviéramos que separar datos específicos (como una tabla de salarios de una tabla de Empleados), podríamos usar 'select_for_update' en la tabla de Empleados sin bloquear la información de salarios. ¿Correcto? – grokpot

23

En realidad, hay una diferencia en dónde coloca el campo de uno a uno, porque la eliminación se comporta de manera diferente. Cuando elimina un objeto, se eliminará cualquier otro objeto que tenga relaciones uno a uno que hagan referencia a ese objeto. Si, por el contrario, elimina un objeto que contiene un campo de uno a uno (es decir, hace referencia a otros objetos, pero otros objetos no hacen referencia a él), no se eliminan otros objetos.

Por ejemplo:

class A(models.Model): 
    pass 

class B(models.Model): 
    a = models.OneToOneField(A) 

Si elimina A, B por defecto se borrarán también (aunque se puede anular esta modificando el argumento on_delete en el OneToOneField al igual que con ForeignKey). Al eliminar B no se eliminará A (aunque puede cambiar este comportamiento anulando el método delete() en B).

Volviendo a su pregunta inicial de has-a vs. is-a, si A tiene B, B debe tener el campo uno-a-uno (B solo debería existir si A existe, pero A puede existir sin SEGUNDO).

0

Por cierto, yo necesitaba OneToOneField para evitar la dependencia circular (uso herencia):

Model A: 
    ... 
    current_choice = models.ForeignKey(B) 

Model B: 
    ... 
    parent = models.ForeignKey(A) 

Eso significa, que necesita un B por definir. No es una buena convención de base de datos para bootstrapping. En lugar de eso hizo:

Model A: 
    ... 

Model B: 
    ... 
    parent = models.ForeignKey(A) 

Model C: 
    parent = models.OneToOneField(A) 
    current_choice = models.ForeignKey(B) 

Con respecto al ejemplo de documentation, también puede tener consultas limpias como: p1.restaurant.place.restaurant.place ... Esto es una locura.

+0

¿Por qué no se dio cuenta de este comportamiento simplemente usando * related_name * en la clave externa? Entonces en el Modelo A podrías hacer 'current_choice = models.ForeignKey (B, related_name = 'parent')' y luego en cada instancia de B ('b = B.objects.first()') puedes hacer 'b.parent 'para buscar el objeto A relacionado. – Kim

+0

Bueno, 'related_name' no es necesariamente uno a uno, sino que se utiliza como una consulta de conjunto la mayor parte del tiempo, por lo que necesita verificar el conteo, etc. El ejemplo anterior es más bien una consulta inmediata ya que se ha forzado a tener un único resultado solamente. – hurturk

Cuestiones relacionadas