django-auto-prefetching 是一个库,它通过在使用django-rest-framework 时使用prefetch_related和select_related从数据库中获取正确的对象来自动优化您的端点。
Django REST 框架和 n+1 问题
Django REST 框架(DRF)是一个用于快速构建强大的 REST API 的框架。然而,当获取具有嵌套关系的模型时,我们会遇到性能问题。DRF 变得缓慢。
这不是由于 DRF 本身,而是由于 n+1 问题。当我们有一个模型时,比如说Article有一个关系Author,我们想要获取所有文章与它们相应的作者。这意味着我们可能会进行大量查询,因为 DRF 首先获取所有文章,然后为每个文章分别获取它们的作者。这意味着如果有 20 篇文章,我们最终将对作者进行 20 个单独的数据库调用。
Django 有一个内置的解决方案来解决这个问题,select_related和prefetch_related,它告诉 ORM 你将需要哪些相关的对象。这意味着我们可以只做一次数据库调用,而不是进行一堆数据库调用。
然而,这有两个问题
- 很难准确跟踪您最终将遍历哪些关系,
- 手动编写select_related和prefetch_related调用很耗时,更不用说在其他地方的代码更改时保持更新。
django-auto-prefetching
这个库的目标是毫不费力地、尽可能轻松地确保您不会因 n+1 问题而遭受性能问题。我们从 DRF 序列化程序的自动预取开始。
安装
pip install django-auto-prefetching
用法
Django-auto-prefetching 有一个 AutoPrefetchViewSetMixin,它查看任何给定序列化器使用的字段,并自动计算正确的select_related和prefetch_related调用。
这意味着一行代码就是您的许多视图将需要的所有优化!
class ChefViewSet(AutoPrefetchViewSetMixin, ModelViewSet):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
手动调用
在AutoPrefetchViewSetMixin不能看到如SerializerMethodField中正在被访问的对象。如果您使用其中的对象,则可能需要进行一些额外的预取。如果你这样做并覆盖get_queryset,你将不得不手动调用prefetch,因为这个mixin的代码是无法达到的。
import django_auto_prefetching
class BaseModelViewSet(django_auto_prefetching.AutoPrefetchViewSetMixin, ModelViewSet):
serializer_class = YourModelSerializer
def get_queryset(self):
queryset = YourModel.objects.all()
queryset = queryset.select_related('my_extra_field')
return django_auto_prefetching.prefetch(queryset, self.serializer_class)