Django:检查外键字段是否已加载

7

我有两个Django模型

class ValidName:
    name = models.TextField()

class MetaSyntacticName(ValidNames):
    name = models.ForeignKey(ValidName)
    usages = models.IntegerField()

如果我有MetaSyntacticName的实例,能否在不进行数据库查询的情况下找出其名称引用的ValidName实例是否已从数据库加载?
4个回答

3

我发现一种方法是使用私有模型实例属性_state。它有一个属性fields_cache,它是一个映射:字段名 -> 字段缓存。

所以在你的情况下,你可以使用以下代码检查外键name是否已加载:

'name' in instance._state.fields_cache

其中instanceMetaSyntacticName的一个实例。

以下代码演示了它的工作原理:

foo = ValidName.objects.create(name='foo')
foo_meta = MetaSyntacticName.objects.create(name=foo, usages=1)
'name' in foo_meta._state.fields_cache  # True
foo_meta = MetaSyntacticName.objects.get(name_id=foo.id)
'name' in foo_meta._state.fields_cache  # False
# next line hits the db and loads the field 'name'
foo_meta.name
'name' in foo_meta._state.fields_cache  # True

我花了一些时间才编写出这个代码,希望这能够为他人节省时间 :)

另外,在测试中,我发现类似的代码在Django 2.2上也可以正常工作。因为_state是一个私有属性,所以在不同的Django版本中可能会有所不同。


3
只是想加入我的意见。我猜在Django 2.x中引入了公共API(请参阅django.db.models.fields.mixins.FieldCacheMixin),因此您可以通过调用MetaSyntacticName.name.is_cached(instance)来检查字段是否已缓存。 - Sergei Zherevchuk

1
如果您调用select_related,则不会有任何额外的数据库查询来预填充ForeignKey相关对象。例如:(从文档中复制粘贴):
# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog

这里是select_related查询:

# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog

1
我不希望我的操作永远填充相关对象。如果它已经被填充,而且有合理的机会是这样的,我想要询问相关对象。但如果它还没有被填充,我只想继续进行下去。 - Jerry Asher

1
您可以像这样添加方法:

您可以像这样添加方法:

class MetaSyntacticName(ValidNames):
    ...

    def valid_name_is_cached(self):
        return __class__.validname_ptr.is_cached(self)

__class__ 只是 MetaSyntacticName

validname_ptr - 是 Django 描述符,其具有 is_cached 方法


0
@sergei-zherevchuk的评论给出了这个问题的现代答案:`MetaSyntacticName.name.is_cached(instance)`或者更一般地说,`Model.field_name.is_cached(model_instance)`现在是最好的方法。
添加这个答案是为了当其他人来搜索时,它可以被正式地作为一个答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接