2009-05-19 4 views
29

Я хочу подключить один ForeignKey к двум различным моделям.Как использовать динамический внешний ключ в Django?

Например:

У меня есть две модели, названные Casts и Articles, а третья модель, Faves, для любой из их в избранное других моделей. Как я могу сделать динамик ForeignKey?

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) 

Возможно ли это?

ответ

37

Вот как я это делаю:

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) 

Вы бы добавить что-то вроде

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

к Faves и

fields.GenericRelation(Faves) 

статьи и Cast

contenttypes docs

15

Вот такой подход. (Обратите внимание, что модели в единственном числе, Django автоматически pluralizes для вас.)

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) 

Это редко представляет серьезные проблемы. Это может потребовать некоторых умных методов класса, в зависимости от ваших вариантов использования.

+10

+1 Я думаю, что общие типы контента, как и в принятом ответе, лучше подходят для «подключаемых» моделей, где вы ничего не знаете об отношениях. Ваш ответ лучше для ситуаций, когда у вас есть контроль и полное знание всех моделей. Лучше означает, что проще писать запросы и меньше ударов по базе данных. –

+2

Вы забыли «null = True» в аргументах поля FK и статьи FK, потому что каждый экземпляр Fave только не устанавливает одно поле FK в None, которое соответствует настройке в поле type_of_fave – Geradeausanwalt

Смежные вопросы