Django 中未保存模型的通用外键

问题描述 投票:0回答:1

我偶然发现 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 foreign-keys django-orm generic-foreign-key
1个回答
0
投票

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
(存储主键的字段)之外,它不会做那么多事情。 

严格来说,可以通过覆盖

.get_db_prep_value(…)

 方法 model 字段[Django-doc]来推迟保存,直到将对象保存到数据库中,但这尚未完成.
    

© www.soinside.com 2019 - 2024. All rights reserved.