现在已经尝试解决这个问题几个小时了,但一无所获。
class other(models.Model):
user = models.ForeignKey(User)
others = other.objects.all()
o = others[0]
此时,ORM 还没有请求 o.user 对象,但如果我做任何触及该对象的操作,它就会从数据库中加载它。
type(o.user)
将导致从数据库加载。
我想了解的是他们是如何做到这一点的。导致它发生的 python Sprite 尘是什么。是的,我查看了源代码,我被难住了。
最佳答案
Django 使用 metaclass ( django.db.models.base.ModelBase
) 自定义模型类的创建。对于模型上定义为类属性的每个对象(user
是我们这里关心的对象),Django 首先查看它是否定义了 contribute_to_class
方法。如果定义了方法,Django 调用它,允许对象在创建模型类时自定义模型类。如果对象没有定义 contribute_to_class
,它只是使用 setattr
分配给类。
由于 ForeignKey
是 Django 模型字段,它定义了 contribute_to_class
.当 ModelBase
元类调用 ForeignKey.contribute_to_class
时,分配给 ModelClass.user
的值是 django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor
的实例.
ReverseSingleRelatedObjectDescriptor
是一个实现 Python 的 descriptor protocol 的对象。为了自定义当类的实例作为另一个类的属性被访问时会发生什么。在这种情况下,描述符用于lazily load并在第一次访问时从数据库中返回相关的模型实例。
# make a user and an instance of our model
>>> user = User(username="example")
>>> my_instance = MyModel(user=user)
# user is a ReverseSingleRelatedObjectDescriptor
>>> MyModel.user
<django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor object>
# user hasn't been loaded, yet
>>> my_instance._user_cache
AttributeError: 'MyModel' object has no attribute '_user_cache'
# ReverseSingleRelatedObjectDescriptor.__get__ loads the user
>>> my_instance.user
<User: example>
# now the user is cached and won't be looked up again
>>> my_instance._user_cache
<User: example>
每次在模型实例上访问 user
属性时都会调用 ReverseSingleRelatedObjectDescriptor.__get__
方法,但它足够聪明,只查找相关对象一次然后在后续调用中返回缓存版本。
关于python - Django 的 ORM 如何在访问外部对象时设法获取它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3597762/