我有两个Django模型
class ValidName:
name = models.TextField()
class MetaSyntacticName(ValidNames):
name = models.ForeignKey(ValidName)
usages = models.IntegerField()
如果我有MetaSyntacticName的实例,能否在不进行数据库查询的情况下找出其名称引用的ValidName实例是否已从数据库加载?
我有两个Django模型
class ValidName:
name = models.TextField()
class MetaSyntacticName(ValidNames):
name = models.ForeignKey(ValidName)
usages = models.IntegerField()
我发现一种方法是使用私有模型实例属性_state
。它有一个属性fields_cache
,它是一个映射:字段名 -> 字段缓存。
所以在你的情况下,你可以使用以下代码检查外键name
是否已加载:
'name' in instance._state.fields_cache
其中instance
是MetaSyntacticName
的一个实例。
以下代码演示了它的工作原理:
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版本中可能会有所不同。
# 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
您可以像这样添加方法:
class MetaSyntacticName(ValidNames):
...
def valid_name_is_cached(self):
return __class__.validname_ptr.is_cached(self)
__class__ 只是 MetaSyntacticName
validname_ptr - 是 Django 描述符,其具有 is_cached 方法
MetaSyntacticName.name.is_cached(instance)
来检查字段是否已缓存。 - Sergei Zherevchuk