Skip to main content

使用 select_related()、prefetch_related()、defer() 和 only() 自动优化序列化器

项目描述

汽车相关

AutoRelated 包自动为 django-rest 序列化程序创建正确的 djangoselect_related()prefetch_related()方法。only()

  • 将您的序列化程序传递给 Tracer 对象
  • 使用返回的参数构建您的查询
  • 您的查询已优化

要求

AutoRelated 是针对其开发和测试的;

  • Django 版本:3.0、3.0.5
  • Django REST 框架版本:3.10.3、3.11.0
  • Python 版本:3.6、3.7、3.8

它只需要:

  • 姜戈
  • Django REST 框架

除上述以外的开发:

  • Django 调试工具栏

安装

要安装它,请使用

$ pip install auto-related

用法

如果您在 serializers.py 文件中定义了这样的序列化程序;

from restframework import serializers

class SomeSerializer(serializer.ModelSerializer):
    field=SomeotherSerializer(many=True)
    .
    .
    .

你可以像这样在你的视图中使用它;

from auto_related.tracer import Trace, optimized_queryset_given_trails
from rest_framework import status,generics

class ParentList(generics.ListAPIView):
    serializer_class = SomeSerializer
    def get_queryset(self):
        t=Tracer(SomeSerializer)
        traces=t.trace()
        s,p=optimized_queryset_given_trails(traces)
        return SomeSerializer.model.objects.select_related(*s)\
                                            .prefetch_related(*p)\
                                            .only(*t.build_only())

或者你可以使用基本上做同样事情的mixin

from auto_related.mixin import ViewMixin, ViewMixinWithOnlyOptim
from rest_framework import status,generics

#this mixin does not use only() and defer() optimization
class ParentList(ViewMixin, generics.ListAPIView):
    serializer_class = SomeSerializer
    # you can pass extra parameters here for SerializerMethodField if you do not use auto-related's MethodField
    queryset=Parent.objects.all() 

#this mixin uses only() and defer() optimization
class ParentList(ViewMixinWithOnlyOptim, generics.ListAPIView):
    serializer_class = SomeSerializer
    queryset=Parent.objects.all()
如果你有一个 SerializerMethodField:

如果您的序列化程序中有一个 SerializerMethodField 需要评估一个查询集,那么它无法通过自动相关自动检测到,因为检查一个函数真的很困难。作为一种解决方案,您可以使用来自 auto-related.method_field 的 MethodField,它与 SerializerMethodField 几乎相同,只是它有一个 sources 属性,稍后可用于 auto-related 确定正确使用 select_related()、prefetch_related() 并且仅()。

from auto_related.method_field import MethodField
class SomeSerializerWithMethodField(serializer.ModelSerializer):
    field1=MethodField(many=True, sources=['related_object_set'])
    field2=MethodField(many=True, sources=['child__related_object_set', 'related_object_set'])

    get_field1(self, obj):
        # here related_object is accessed hence it sould be added to sources 
        return obj.related_object_set.all().count()

    get_field2(self, obj):
        # here related_object and child.related_object is accessed hence they sould be added to sources 
        return obj.child.related_object_set.all().count() + obj.related_object_set.all().count()

    class Meta:
        model=modelA

class AnotherSerializer(serializer.ModelSerializer):
    # You can use above serializer which includes a SerializerMethodField in another serializer safely.
    # This way you do not need to deal with nested usage of SerilizerMethodField. 
    # They are automatically prepended with necessary model and field names when used in another serializer.
    # Also sources are automatically splitted into select_related and prefetch_related in a way 
    # which minimizes database hits.
    field=SomeSerializerWithMethodField(many=True, source='modelA')

    class Meta:
        model=modelB

MethodField 的实现与 rest-framework 中的 SerializerMethodField 几乎相同。事实上,如果你不向它传递 sources 参数,它是一样的。auto_related.method_field import MethodField as SerializerMethodField因此,您可以在不更改代码的情况下导入 like ,并且您只需为必要的字段设置源参数。

这个怎么运作

首先,一个 util 函数get_all_sources()通过遍历它的所有字段(包括嵌套的序列化器的字段)来深入检查一个序列化器。假设您有这样的序列化程序;

class SomeSerializer(serializer.ModelSerializer):
    field=SomeOtherSerializer(many=True, source='some_other')
    text=CharField()

class SomeOtherSerializer(serializer.ModelSerializer):
    name=CharField()
    attr=IntegerField()     

然后通过以下方式获得序列化器的所有源;

get_all_sources(SomeSerializer)
#returns ['field', 'text',' some_other.name', 'some_other.attr']

这是该序列化程序在与数据一起传递时将访问的所有属性。我们必须以某种方式检查这些来源以决定要预取什么。

然后,跟踪器对象在此序列化程序分配到的模型上跟踪所有这些源。例如 some_other.attr 源首先访问 some_other 关系字段,然后访问 SomeOther 模型的 attr integerfield。请注意,这些字段与其余框架字段无关,它们是 django 的字段对象。字段帮助我们决定预取什么。例如,如果一个字段是相关或反向相关的字段,那么可以说它应该被预取。然而,在 django 中有两种方法可以做到这一点,它们是select_relatedprefetch_related. 字段类有助于确定哪个是哪个。例如,可以使用 onetoone 字段预取,select_related但我们应该使用prefetch_relatedmanytomany 字段或反向相关字段等。

发展

想贡献?伟大的!

目前没有自动化测试。您可以克隆 repo 并运行测试项目;

$ cd projectfolder/autorelated/tests
$ python manage.py runserver

项目中安装了 Django 工具栏,以便您可以检查执行了多少查询以及许多其他事情以用于测试目的。例如,您可以去比较 auto_related 应用http://localhost:8080/test/coursehttp://localhost:8080/test/course/slow未应用查询之间的速度和查询计数差异。测试项目中的每个 url 都有其对应部分...url/slow,它不使用 auto_related 并且仅用model.objects.all()作查询集。

待办事项

  • 写作测试
  • 检查传递给序列化程序的查询集或模型实例,以检查它们是否被缓存和正确配置,如果没有自动优化它们。
  • 在不需要 django 模型实例时使用values()而不是使用。only()
  • 为了能够将整个包用作调试工具,当 DEBUG=True 时,它​​可以警告缺少优化

执照

麻省理工学院

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

auto_related-0.0.4.tar.gz (11.0 kB 查看哈希)

已上传 source

内置分布

auto_related-0.0.4-py3-none-any.whl (10.1 kB 图哈希)

已上传 py3