2009-07-11 16 views
10

Básicamente, tengo un modelo donde he creado una superclase que comparten muchas otras clases, y cada una de esas clases tiene algunas características únicas que difieren entre sí. Digamos que la clase A es la superclase, y la clase B, C y D son hijos de esa clase.Herencia de modelo de Django y claves externas

Tanto la clase B como la clase C pueden tener múltiples clases de clase D, sin embargo, he visto que es mejor poner la relación de clave foránea en la clase D, que luego se refiere a su clase principal. Ahora, en otros idiomas, podría decir simplemente que tiene una relación ForeignKey con la clase A, y luego el lenguaje reconoce el tipo verdadero de las clases. Sin embargo, no creo que sea así como funciona con Python.

¿Cuál es la mejor forma recomendada de resolver este problema?

EDIT: Aquí es más o menos lo que quiero decir ...

class A(models.Model): 
    field = models.TextField() 

class B(A): 
    other = <class specific functionality> 

class C(A): 
    other2 = <different functionality> 

class D(A): 
    #I would like class D to have a foreign key to either B or C, but not both. 

Esencialmente, clase B y clase C que ambos tienen múltiples clases D's. Pero una clase particular D solo pertenece a uno de ellos.

+0

¿Podría explicar por qué necesita herencia? – Evgeny

+0

Hay una pregunta relacionada que tiene algunas buenas respuestas que pueden ayudar: https://stackoverflow.com/questions/1114767/django-model-inheritance-and-foreign-keys – Miranda

Respuesta

3

Desde el Django Docs:

Por ejemplo, si alguien quisiera construir una base de datos de "lugares", se podía construir cosas bastante estándar, tales como dirección, número de teléfono , etc. la base de datos. Entonces, si usted quiere construir una base de datos de los restaurantes en la parte superior de los lugares, en lugar de repetir siempre lo mismo y replicar esos campos en el modelo restaurante, usted podría hacer restaurante tiene un OneToOneField a Lugar (debido a un restaurante "es un lugar" ; de hecho, para manejar esto, suele usar herencia, que implica una relación uno a uno implícita ).

Normalmente, solo tendrías Restaurant heredar de Place.Lamentablemente, lo que necesita lo que considero un truco: hacer una referencia de uno a otro de subclase de la superclase (Restaurant a Place)

+0

¿No proporciona django una referencia uno a uno por defecto? p.ej. para los modelos heredados de varias tablas, "restaurant.place" devuelve la instancia correspondiente de Lugar, sin la necesidad de que el usuario defina ninguna relación que no sea la herencia. –

+3

tal vez lo haga ahora, pero no creo que haya sucedido en * 2009 *. – geowa4

+0

¡Ya veo, gracias! xxx –

1

veo un problema aquí:

class D(A): 
    #D has foreign key to either B or C, but not both. 

no pueden hacerlo. Tendrá que agregar ambos porque en SQL las columnas se deben definir exactamente.

También aunque los modelos heredados como usted han compilado con syncdb - no parecen comportarse como era de esperar - al menos no pude hacerlos funcionar. No puedo explicar por qué.

Esto es como FK trabaja en Django

class A(models.Model): 
    a = models.CharField(max_length=5) 

class B(models.Model): 
    a = model.ForeignKey(A, related_name='A') 
    b = models.CharField(max_length=5) 

class D(models.Model): 
    a = model.ForeignKey(A, related_name='A') 
    parent = model.ForeignKey(B, related_name='D') 

esta manera usted puede tener eficacia en múltiplos de D B.

herencia en los modelos (por ejemplo, la clase B (A)) no funciona como Lo esperaría. Quizás alguien más pueda explicarlo mejor.

Eche un vistazo a this doc página. Se trata de la relación muchos a uno en django.

b = B() 
b.D_set.create(...) 
+0

Mi problema es que me gustaría que la clase D pertenezca a ya sea una Clase A o una Clase B y no ambas. Voy a aclarar en mi pregunta. – AlbertoPL

1

Una forma de hacer esto es añadir una clase intermedia como sigue:

class A(Model): 
    class Meta(Model.Meta): 
     abstract = True 
    # common definitions here 

class Target(A): 
    # this is the target for links from D - you then need to access the 
    # subclass through ".b" or ".c" 
    # (no fields here) 

class B(Target): 
    # additional fields here 

class C(Target): 
    # additional fields here   

class D(A): 
    b_or_c = ForeignKey(Target) 
    def resolve_target(self): 
     # this does the work for you in testing for whether it is linked 
     # to a b or c instance 
     try: 
      return self.b_or_c.b 
     except B.DoesNotExist: 
      return self.b_or_c.c 

Uso de una clase intermedia (Target) garantiza que sólo habrá un enlace de D a B o C. ¿Eso ¿tener sentido? Vea http://docs.djangoproject.com/en/1.2/topics/db/models/#model-inheritance para más información.

En su base de datos habrá tablas para Target, B, C y D, pero no A, porque eso se marcó como abstracto (en cambio, las columnas relacionadas con los atributos de A estarán presentes en Target y D).

[Advertencia: en realidad no he probado este código - ¡cualquier corrección es bienvenida!]

+0

Muy hacky. Aunque funcionaría. – clime

Cuestiones relacionadas