Django:如何预取模型实例的相关内容。也许通过包装查询集?

Jad*_*d S 5 python django query-optimization django-rest-framework

我使用 Django Rest 框架,并且我的模型关系中有不错的嵌套。

我正在努力优化我的查询。我的许多函数都会消耗或操作模型的单个实例,并且通常在数据流的更下游,事实证明我需要一些预取。一个典型的例子是 DRF 序列化器。这是一个例子。

@api_view(['GET'])
def fetch_user_profile(request):
    profile = request.user.profile # has many nested relationships

    return Response(UserProfileSerializer(profile).data, status=status.HTTP_200_OK) # this ends up taking many queries
Run Code Online (Sandbox Code Playgroud)

我已经看到一些解决方案建议在上下文中传递查询集,prefetch_related尽管我无法全面了解它是如何工作的(我只找到了几个部分讨论它的地方,可能会打开一个完整的其他地方的问题)。

一个简单的修复(并且可以推广到序列化器之外的修复)是,如果我可以有一个包装函数将我的实例包装在查询集中,然后对其调用预取,将其传递到序列化器中。

就像是:

def queryset_wrap(instance):
    return type(instance).objects.filter(id=instance.id)
Run Code Online (Sandbox Code Playgroud)

我想知道是否有更好的方法来做到这一点。

小智 5

我自己还没有使用过这个,但我相信它是prefetch_related_objects()您正在寻找的功能,在 Django 1.10 中引入

来自文档

在可迭代的模型实例上预取给定的查找。这在接收模型实例列表而不是查询集的代码中非常有用;例如,从缓存中获取模型或手动实例化它们时。

传递模型实例的可迭代对象(必须全部属于同一类)以及要预取的查找或预取对象。例如:

>>> from django.db.models import prefetch_related_objects
>>> restaurants = fetch_top_restaurants_from_cache()  # A list of Restaurants
>>> prefetch_related_objects(restaurants, 'pizzas__toppings')
Run Code Online (Sandbox Code Playgroud)

由于它需要一个可迭代对象,因此您可以将实例包装在列表中:

prefetch_related_objects([profile], "relevant_attribute_1", "relevant_attribute_2")
Run Code Online (Sandbox Code Playgroud)