2009-05-19 17 views
29

Quiero conectar un solo ForeignKey a dos modelos diferentes.¿Cómo se usa la clave externa dinámica en Django?

Por ejemplo:

Tengo dos modelos nombrados Casts y Articles, y un tercer modelo, Faves, para favoriting cualquiera de los otros modelos. ¿Cómo puedo hacer que el ForeignKey sea dinámico?

class Articles(models.Model): 
    title = models.CharField(max_length=100) 
    body = models.TextField() 

class Casts(models.Model): 
    title = models.CharField(max_length=100) 
    body = models.TextField() 

class Faves(models.Model): 
    post = models.ForeignKey(**---CASTS-OR-ARTICLES---**) 
    user = models.ForeignKey(User,unique=True) 

¿Esto es posible?

Respuesta

37

Aquí es cómo lo hago:

from django.contrib.contenttypes.models import ContentType 
from django.contrib.contenttypes import fields 


class Photo(models.Model): 
    picture = models.ImageField(null=True, upload_to='./images/') 
    caption = models.CharField(_("Optional caption"),max_length=100,null=True, blank=True) 

    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = fields.GenericForeignKey('content_type', 'object_id') 

class Article(models.Model): 
    .... 
    images  = fields.GenericRelation(Photo) 

Se podría añadir algo como

content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = fields.GenericForeignKey('content_type', 'object_id') 

a tus juegos favoritos y

fields.GenericRelation(Faves) 

con el artículo y Elenco

contenttypes docs

15

Aquí hay un enfoque. (Tenga en cuenta que los modelos son singulares, Django pluralice automáticamente.)

class Article(models.Model): 
    title = models.CharField(max_length=100) 
    body = models.TextField() 

class Cast(models.Model): 
    title = models.CharField(max_length=100) 
    body = models.TextField() 

FAVE_CHOICES = ( 
    ('A','Article'), 
    ('C','Cast'), 
) 
class Fave(models.Model): 
    type_of_fave = models.CharField(max_length=1, choices=FAVE_CHOICES) 
    cast = models.ForeignKey(Casts,null=True) 
    article= models.ForeigKey(Articles,null=True) 
    user = models.ForeignKey(User,unique=True) 

Esto rara vez presenta problemas profundos. Puede requerir algunos métodos de clase inteligentes, según sus casos de uso.

+10

+1 Creo que los tipos de contenido genéricos, como en la respuesta aceptada, son mejores para los modelos "conectables" en los que no se conoce nada sobre las relaciones. Su respuesta es mejor para situaciones donde tiene control y conocimiento completo de todos los modelos. Mejor significa que es más fácil escribir consultas y menos visitas en la base de datos. –

+2

Olvidó "null = True" en los argumentos de campo fundido y artículo FK porque cada instancia de Fave no establecerá el único campo FK en Ninguno que corresponde a la configuración en el campo type_of_fave – Geradeausanwalt

Cuestiones relacionadas