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

auto-related的Python项目详细描述


自相关

AutoRelated包自动为django rest序列化程序创建正确使用django的select_related()prefetch_related()和{}方法。在

  • 将序列化程序传递给跟踪对象
  • 使用返回的参数生成查询
  • 您的查询已优化

要求

开发和测试自相关

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

它只需要:

  • Django公司
  • Django REST框架

除上述开发外:

  • Django调试工具栏

安装

要安装它,请使用

$ pip install auto-related

使用

如果在序列化程序.py文件

^{pr2}$

你可以这样在你的观点中使用它

fromauto_related.tracerimportTrace,optimized_queryset_given_trailsfromrest_frameworkimportstatus,genericsclassParentList(generics.ListAPIView):serializer_class=SomeSerializerdefget_queryset(self):t=Tracer(SomeSerializer)traces=t.trace()s,p=optimized_queryset_given_trails(traces)returnSomeSerializer.model.objects.select_related(*s)\
                                            .prefetch_related(*p)\
                                            .only(*t.build_only())

或者你可以使用mixin来做同样的事情

fromauto_related.mixinimportViewMixin,ViewMixinWithOnlyOptimfromrest_frameworkimportstatus,generics#this mixin does not use only() and defer() optimizationclassParentList(ViewMixin,generics.ListAPIView):serializer_class=SomeSerializer# you can pass extra parameters here for SerializerMethodField if you do not use auto-related's MethodFieldqueryset=Parent.objects.all()#this mixin uses only() and defer() optimizationclassParentList(ViewMixinWithOnlyOptim,generics.ListAPIView):serializer_class=SomeSerializerqueryset=Parent.objects.all()
如果您有一个serializermethod字段:

如果在序列化程序中有一个SerializerMethodField,它需要求值一个queryset,那么它就不能被auto-related自动检测到,因为检查函数确实很困难。作为解决方案,您可以使用auto中的MethodField-相关方法字段它与SerializerMethodField几乎相同,只是它有一个sources属性,稍后auto-related可以使用它来确定select_-related()、prefetch_-related()和only()的正确使用。在

fromauto_related.method_fieldimportMethodFieldclassSomeSerializerWithMethodField(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 returnobj.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 returnobj.child.related_object_set.all().count()+obj.related_object_set.all().count()classMeta:model=modelAclassAnotherSerializer(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')classMeta:model=modelB

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

工作原理

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

classSomeSerializer(serializer.ModelSerializer):field=SomeOtherSerializer(many=True,source='some_other')text=CharField()classSomeOtherSerializer(serializer.ModelSerializer):name=CharField()attr=IntegerField()

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

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

这是序列化程序在与数据一起传递时将访问的所有属性。我们不得不检查这些数据源来决定预取什么。在

然后,tracer对象跟踪这个序列化程序分配到的模型上的所有这些源。例如一些_其他属性source首先访问一些其他关系字段,然后访问其他模型的attr integerfield。请注意,这些字段与rest框架字段无关,它们是django的field对象。字段帮助我们决定预取什么。例如,如果一个字段是相关字段或反向相关字段,那么可以说它应该被预取。但是在django中有两种方法可以做到这一点,它们是select_related和{}。Fields类帮助决定哪个是哪个。例如,一个onetoone字段可以使用select_related进行预取,但是我们应该使用prefetch_related来表示许多字段或反转相关字段等。。在

发展

想做贡献吗?太好了!在

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

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

Django toolbar安装在项目中,这样您就可以检查执行了多少查询,以及其他许多测试。例如,您可以转到http://localhost:8080/test/coursehttp://localhost:8080/test/course/slow,比较与自动相关的已应用查询和未应用查询之间的速度和查询计数差异。测试项目中的每个url都有其计数器部分...url/slow,它不使用auto相关的,只使用model.objects.all()作为查询集。在

待办事项

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

麻省理工学院

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
JFrame中的Java多线程   java Servlet异常映射   java无法从输出流读取   swing Java带来的小程序GUI问题   java什么原因导致错误“'void'类型此处不允许”以及如何修复它?   Java选择器select(长)与selectNow的区别   java自定义arraylist<mygames>获得不同   java Icepdf注释让页面消失   java反向整数数组   java I在生成同步“无法解析配置的所有依赖项”时遇到此错误:app:debugRuntimeClasspath   多个虚拟机上的java线程访问单个DB实例上的表,有时会导致性能低下和异常   swing更改Java中的默认按钮,使其看起来“更好”   java慢速MQ主题订阅。并行化不能提高性能   java运行Boggle Solver需要一个多小时。我的代码怎么了?   数据库中的java循环与应用程序中的java循环   正则表达式匹配${123…456}并在Java中提取2个数字?   java如何制作我们软件的试用版   Java内存参数计算   从另一个类调用方法时出现java问题