详解Django的 defer() 函数:排除指定的字段

  • Post category:Python

在Django中,一次查询可能会返回多个关联模型,这些模型往往带有关联模型的查询负担。此时可以使用defer()函数,将模型中的某些字段从查询中延迟加载,提高查询效率。

使用方法

defer()函数需要在查询集上调用,它接受若干个参数,用于指定要延迟加载的字段名。对于延迟加载的字段,在访问时会重新发起数据库查询。

举例如下:

from myapp.models import MyModel

# 查询 MyModel 的所有数据,延迟加载字段为 "my_field"
qs = MyModel.objects.defer("my_field").all()

for obj in qs:
    # 此时访问 my_field 字段会重新执行 SQL查询
    print(obj.my_field)

实例说明

例一:对比查询时间

对于一个大型数据表,使用defer()函数可以显著提高查询时间。考虑下面的代码:

# 没有使用 defer() 的查询
start_time = time.time()
objs = MyModel.objects.all()
for obj in objs:
    print(obj.my_field)
print("Execution time:", time.time() - start_time)

# 使用 defer() 的查询
start_time = time.time()
objs = MyModel.objects.defer("my_field").all()
for obj in objs:
    print(obj.my_field)
print("Execution time:", time.time() - start_time)

在上述代码中,我们通过比较两次查询的执行时间,可以发现使用 defer函数能够显著提高查询效率。

例二:延迟加载关联模型的字段

考虑一个模型多关联模型的场景,模型间存在多对多关系。在下面的代码中,我们使用select_related()函数提前加载了所有与模型相关的数据,然后使用defer()函数延迟加载MyModel1MyModel2两个模型中的一些字段。

from myapp.models import MyModel, MyModel1, MyModel2

qs = MyModel.objects.select_related("my related model").defer("MyModel1__my_field1", "MyModel2__my_field2")

在这个例子中,MyModel, MyModel1, MyModel2 之间的关系形如:

  • MyModel通过related_model外键字段关联到 MyModel1
  • MyModel1 通过额外一个外键关联到 MyModel2

最后返回的查询集qs将不包括MyModel1或者MyModel2中延迟加载的字段,并且在访问这些字段时需要额外的数据库查询。