我偶然发现 Django 中的外键和通用外键有点不一致。假设我们有三个模型
class Model_One(models.Model):
name= models.CharField(max_length=255)
class Model_with_FK(models.Model):
name=models.CharField(max_length=255)
one=models.ForeignKey(Model_One, on_delete=models.CASCADE)
class Model_With_GFK(models.Model):
name=models.CharField(max_length=255)
content_type= models.ForeignKey(
ContentType, on_delete=models.CASCADE,
)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
class Meta:
indexes=[models.Index(fields=["content_type", "object_id"]), ]
当我们这样做时
one = Model_One()
two = Model_Two(model_one=one)
one.save()
two.save()
一切正常。模型一收到一个 ID,模型二保存后,该 ID 将用于引用模型一。然而,这对 GFK 不起作用
one = Model_One()
two = Model_With_GFK(content_object=one)
one.save()
two.save()
当尝试保存两个时,会引发完整性错误,“object_id”列为空。当使用调试器检查时,模型一保存后,模型二上的字段“content_object”就会从模型“一”变为“无”。这是很出乎意料的,因为使用外键就不存在这样的问题。
当然,您可以在将模型一用于 GFK 关系之前保存它,但为什么这是必要的呢?使用外键,我可以实例化所有模型,然后使用bulk_create 创建它们。有了图中的 GFK,这似乎不再可能了
Django 的
GenericForeignKey
是以一种更“无聊”的方式实现的。事实上,它可以与 .set(…)
描述符 [GitHub]: 一起使用
因此,除了查找def __set__(self, instance, value): ct = None fk = None if value is not None: ct = self.get_content_type(obj=value) fk = value.pk setattr(instance, self.ct_field,ct) setattr(instance, self.fk_field, fk) self.set_cached_value(instance, value)
content_type
和您选择的值的主键,并设置
ct_field
(内容类型)和
fk_field
(存储主键的字段)之外,它不会做那么多事情。严格来说,可以通过覆盖 方法 model 字段[Django-doc]来推迟保存,直到将对象保存到数据库中,但这尚未完成.