几个小时以来一直试图解决这个问题,但一无所获。
class other(models.Model):
user = models.ForeignKey(User)
others = other.objects.all()
o = others[0]
此时,ORM 尚未请求 o.user 对象,但如果我执行任何涉及该对象的操作,它就会从数据库加载它。
type(o.user)
将导致数据库加载。
我想了解的是他们是如何施展这种魔法的。导致这种情况发生的蟒蛇精灵尘埃是什么?是的,我看了源码,我被难住了。
Django 使用一个元类 http://docs.python.org/reference/datamodel.html#customizing-class-creation (django.db.models.base.ModelBase http://code.djangoproject.com/browser/django/trunk/django/db/models/base.py#L22) 自定义模型类的创建。对于模型上定义为类属性的每个对象(user
是我们在这里关心的),Django 首先查看它是否定义了一个contribute_to_class
方法。如果定义了该方法,Django 就会调用它,从而允许对象在创建时自定义模型类。如果对象没有定义contribute_to_class
,它只是简单地分配给类使用setattr
.
Since ForeignKey
是一个 Django 模型字段,它定义contribute_to_class http://code.djangoproject.com/browser/django/trunk/django/db/models/fields/related.py#L872。当。。。的时候ModelBase
元类调用ForeignKey.contribute_to_class
,分配给的值ModelClass.user
是一个实例django.db.models.fields.related.ReverseSingleRelatedObjectDescriptor http://code.djangoproject.com/browser/django/trunk/django/db/models/fields/related.py#L266.
ReverseSingleRelatedObjectDescriptor
是一个实现Python的对象描述符协议 http://docs.python.org/reference/datamodel.html#descriptors为了自定义当类的实例作为另一个类的属性访问时会发生什么。在这种情况下,描述符用于延迟加载 http://en.wikipedia.org/wiki/Lazy_loading并在第一次访问时从数据库返回相关模型实例。
# 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>
The ReverseSingleRelatedObjectDescriptor.__get__
每次调用方法user
属性是在模型实例上访问的,但它足够智能,只需查找相关对象一次,然后在后续调用时返回缓存的版本。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)