Django REST Framework:由于模型__str__方法

时间:2016-09-22 01:39:01

标签: django django-rest-framework

我正在开发一个带有Django后端的webapp,它为前端提供了一个Django REST Framework API。我最近遇到了一些性能问题,因此我开始调查每个端点的性能 - 其中大多数都向数据库发出了太多查询。

我有几个与预取相关的问题,我无法弄清楚,但这是(我认为)最简单的问题。我已经尽可能地实施了select_relatedprefetch_related,感谢文档和this excellent post关于如何考虑热切加载的问题。

对于一个特定的模型,我已经很好地减少了查询的数量,但我无法弄清楚为什么我仍然有一些重复。

models.py

class ReadingGroup(models.model):
    owner = models.ForeignKeyField(settings.AUTH_USER_MODEL)
    users = models.ManyToManyField(settings.AUTH_USER_MODEL)
    book_type = models.ForeignKeyField(BookType)
    ....
    <other group related fields>

   def __str__(self):
    return '%s group: %s' % (self.name, self.book_type)

serializers.py

class ReadingGroupSerializer(serializers.ModelSerializer):
  users = UserSerializer(many = True,read_only=True)
  owner = UserSerializer(read_only=True)

  class Meta:
    model = ReadingGroup
    fields = ('url', 'id','owner', 'users')

  @staticmethod
  def setup_eager_loading(queryset):
    #select_related for 'to-one' relationships
    queryset = queryset.select_related('owner')

    #prefetch_related for 'to-many' relationships
    queryset = queryset.prefetch_related('users')

    return queryset

views.py

class ReadingGroupViewset(views.ModelViewset):
    def get_queryset(self):
       qs = ReadingGroup.objects.all()
       qs = self.get_serializer_class().setup_eager_loading(qs)
       return qs

urls.py

router.register(r'groups', ReadingGroupViewset)

setup_eager_loading()方法减少了将数据库中的所有12个ReadingGroup实例从40个检索到17个的查询数量,其中12个查询是重复的。每个重复查询都是在每个模型实例上单独调用模型__str__方法的结果。

我最初认为这是因为DRF docs中的某些内容表明__str__方法仅在可浏览的API中使用:

  

模型的内置 str 方法将用于生成用于填充choices属性的对象的字符串表示。这些选项用于在可浏览的API中填充选定的HTML输入。

然而,情况似乎并非如此。我为Django调试工具栏实现了一个解决方法,用于在HTML中包装JSON响应(因为工具栏只配置HTML响应),将?format=json添加到端点请求(因此可以浏览可浏览的API),但重复的查询仍然存在发出的。

DRF是否调用__str__方法,尽管没有使用可浏览的API进行请求,或者我的模型是否存在其他问题?

这可能是由于与使用ModelViewset相关的行为造成的吗?我正在进行此测试的端点仅为/api/groups/,这是register()命令自动生成的URL之一。

编辑:@serg下面的评论让我思考 - 如果它在查询序列化程序中没有的字段,我想它不会受到伤害预取它也是。将book_type添加到setup_eager_loading可以摆脱重复的查询:

@staticmethod
def setup_eager_loading(queryset):
  #select_related for 'to-one' relationships
  queryset = queryset.select_related('owner')
  queryset = queryset.select_related('book_type')

  #prefetch_related for 'to-many' relationships
  queryset = queryset.prefetch_related('users')

  return queryset

我在上面的代码中添加了该字段,因此__str__方法访问关系字段时更清楚。

0 个答案:

没有答案