1

有人写过这个models.py

documents = generic.GenericRelation(Document)

我想知道它与其他类型(如ForeignKeyOneToMany字段)有何不同。

我没有看到足够的文档

如果在这里找到东西

但即使首先,我也不明白 contentype 做了什么以及为什么要使用它。

4

1 回答 1

3

想象一下,您的数据库中有各种对象(图像、视频、歌曲等),并且您希望为每个对象添加关键字。但是,您希望有一个关键字表,它将管理所有带有关键字的对象的所有关键字。所以模型看起来像:

class Image(models.Model):
    # ...

class Video(models.Model):
    # ...

class Keyword(models.Model):
    keyword = models.CharField(max_length=64)

因此,有了模型,您需要以某种方式将关键字连接到其他对象。为此,您需要使用多对多关系:

class KeywordItem(models.Model):
    keyword = models.ForeignKey('Keyword')
    image = models.ForeignKey('Image')

但是这不起作用,因为这只会让您为图像添加关键字,但是您还需要为视频等添加关键字。换句话说,这种方法的问题在于它限制了将关键字链接到特定表,图像表。所以想法不是这样做,而是链接到任何表,然后只需指定要链接到哪个表:

class KeywordItem(models.Model):
    keyword = models.ForeignKey('Keyword')
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey('content_type', 'object_id')

content_type指定您要链接到哪个表,并指定您要链接到的object_id表中的行的主键是什么。

现在的问题是如何指定要链接到哪个表?一种解决方案是对选择进行硬编码(图像是1,视频是2等),但这很容易出错,因为必须对其进行维护。事实证明,Django 通过使用内容类型框架解决了这个问题。发生的情况是,当您执行 . 时syncdb,Django 为您在项目中拥有的每个表/模型分配一个唯一编号。对我来说,更容易将其视为表类型 id(假设为表 id,因为表本身没有 id)。所以这个数字以后可以用来参考具体的表。

然后,如果图像内容类型(表类型 id)是1,并且您想将关键字与 pk 链接7到具有 pk 的图像11,您可以通过以下方式执行此操作:

KeywordItem.objects.create(keyword_id=7,
                           content_type_id=1,
                           object_id=11)

# or using Django magic (this automatically figures out the content type):
KeywordItem.objects.create(keyword_id=7,
                           object=Image.objects.get(pk=11))

希望这能解释一下为什么您可能需要泛型关系的概念。现在为GenericRelation. 使用上面的示例,假设您想要访问特定图像的所有关键字。您将不得不执行以下操作:

img = Image.object.get(...)
img_type = ContentType.objects.get_for_model(img)
img_keywords = KeywordItem.objects.filter(content_type_id=img_type,
                                          object_id=img.pk)

然而,这看起来并不干净,这就是GenericRelation有用的原因。它使访问反向泛型关系变得非常容易。为此,您必须将以下字段添加到Image模型中:

class Image(models.Model):
    # ...
    keywords = generic.GenericRelation('KeywordItem')

现在,这将允许您通过简单地执行以下操作来访问关键字:

Image.object.get(...).keywords.all()

注意事项

通用外键是一项棘手的工作,尤其是在 Django 中,因为语法有些棘手。如果你是 Django 的初学者,我不建议你对它们做任何事情,直到你对 Django 中的外键和 Django 提供的所有“魔法”(例如related_name参数)感到满意。一旦你理解了这一点,通用外键将更容易理解和使用。

于 2012-10-15T04:20:06.080 回答