2012-04-27 16 views
13

¿Es posible obtener el modelo relacionado de una clave externa a través del campo de la clave externa en sí?clave externa de Django: obtener modelo relacionado?

Por ejemplo, si tengo 3 modelos:

class ModelA(models.Model) 
    field1 = models.CharField(max_length=10) 

class ModelB(models.Model) 
    field1 = models.CharField(max_length=10) 

class ModelC(models.Model) 
    field1 = models.CharField(max_length=10) 
    field2 = models.ForeignKey(ModelA) 
    field3 = models.ForeignKey(ModelB) 

y yo quiero hacer:

for field in ModelC._meta.fields: 
    if field.get_internal_type() == "ForeignKey": 
     #get the related model for field e.g. ModelA or ModelB 

Es esto posible utilizando sólo los propios modelos en lugar de las instancias de los modelos?

Respuesta

19

Si ModelA tiene un campo FK llamado "foo", entonces esto es cómo se puede obtener el modelo relacionado:

ModelA._meta.get_field('foo').rel.to 

con su código, que se vería así:

for field in ModelC._meta.fields: 
    if field.get_internal_type() == "ForeignKey": 
     print field.rel.to 

Si lo descubrí usando la terminación de pestañas en el shell hace mucho tiempo, todavía funciona. Es posible que desee aprender a usar el caparazón para aplicar técnicas de ingeniería inversa de esa manera.

+0

Actualización: En Django 2.0 recientemente lanzado, parece que "rel" ya no es un campo de ForeignKey. Puede intentar: 'ModelA._meta.get_field ('foo'). Related_model'. Lo soluciono escribiendo "tab" para completar automáticamente en la línea de comandos. –

0

Al tratar de extraer relaciones como esta, uso mucha experimentación en línea de comandos. Un patrón común que uso es _=starting_point.<chained_attributes>;pprint((_, dir(_))). Por ejemplo:

_=ModelC;pprint((_, dir(_))) 
_=ModelC.field2;pprint((_, dir(_))) 
_=ModelC.field2.field;pprint((_, dir(_))) 
_=ModelC.field2.field.rel;pprint((_, dir(_))) 
_=ModelC.field2.field.rel.to;pprint((_, dir(_))) 

(Usted tendrá que hacer from pprint import pprint primera, naturalmente.) Eso me permite experimentar con la adición/eliminación atributos hasta que encontrar el artículo que quiero ..., mientras que ver con claridad lo que tengo y lo que está disponible en el siguiente nivel hacia abajo. De esto, obtengo ModelC.field2.field.rel.to == ModelA. El mismo patrón de base se puede usar para explorar relaciones inversas, relaciones de muchos a muchos, comenzando con una instancia en lugar de la clase, etc.

Cuestiones relacionadas