python - Django 的 ORM 如何在访问外部对象时设法获取它们

标签 python django orm

现在已经尝试解决这个问题几个小时了,但一无所获。

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/

相关文章:

python - 正则表达式 - 计算一个单词在文本中出现的次数

python - Django - 给定时区、月份和年份,获取该时区该日期创建的所有帖子

java - 将 @PrePersist 和 @PreUpdate 与 Ebean 和 Play 2.5.x 一起使用不起作用?

java - ORMLite - 强制读取对象具有相同的标识

python - 使用Python将引号转换为Latex格式

python - Eclipse 中的 Django,布置项目

python - Django 告诉最后一个项目是否具有双重排序中的某些属性(order_by)

python - django-braces 访问 mxin 每个 mixin 不同的 login_url 重定向

orm - 在 Symfony2 中无损地删除实体

python - 如何使用mockito修补python中的内置/扩展类型?