有人写过这个models.py
documents = generic.GenericRelation(Document)
我想知道它与其他类型(如ForeignKey
和OneToMany
字段)有何不同。
我没有看到足够的文档
如果在这里找到东西
但即使首先,我也不明白 contentype 做了什么以及为什么要使用它。
想象一下,您的数据库中有各种对象(图像、视频、歌曲等),并且您希望为每个对象添加关键字。但是,您希望有一个关键字表,它将管理所有带有关键字的对象的所有关键字。所以模型看起来像:
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
参数)感到满意。一旦你理解了这一点,通用外键将更容易理解和使用。