【问题标题】:How do I eliminate the extra duplicate queries made?如何消除额外的重复查询?
【发布时间】:2016-09-14 19:15:31
【问题描述】:

我试图在使用 Django Rest Framework 序列化查询集时优化对查询集进行的查询。

模型分布在不同的应用程序上。 AbstractModels

#core.abstractmodels
class BasicModelMixin(models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(max_length=265, unique=True, populate_from='name')

    class Meta:
        abstract = True


#core.abstractmodels
class ExtraBaseModel(models.Model):
    software_license = models.ManyToManyField('meta.License')

    class Meta:
        abstract = True

以及 languages 应用上的 Language 类,

#languages.models
class Language(BasicModelMixin, ExtraBaseModel):
    name = models.CharField(max_length=255, unique=True)
    slug = AutoSlugField(max_length=265, unique=True, populate_from='name')

    releases = models.ManyToManyField(
        'languages.LanguageRelease',
        blank=True,
        related_name="%(app_label)s_%(class)s_related_releases",
        related_query_name="%(app_label)s_%(class)ss_releases")

它有一个从 ExtraBaseModel 继承的 License 字段,即

#meta.License
class License(BasicModelMixin):
    display_name = models.CharField(max_length=25)

当我查询 Language 对象时,它会产生额外的重复查询,我需要消除这些查询。

查询如下,

Language.objects.filter(pk=1).prefetch_related('software_license')

在 7ms 内将查询缩短为 4 个,其中 2 个是重复的。 django-debug-toolbar 的输出是,

SELECT *** FROM "languages_language" WHERE "languages_language"."slug" = '''python'''

SELECT *** FROM "meta_license" INNER JOIN
"languages_language_software_license" ON
("meta_license"."id" 
= "languages_language_software_license"."license_id") 
WHERE
"languages_language_software_license"."language_id"

SELECT *** FROM "meta_license"
Duplicated 2 times. 

SELECT *** FROM "meta_license"
Duplicated 2 times.

如何优化查询?必须对模型进行哪些更改才能使其最小化?

Django 版本 = 1.9.x |蟒蛇版本:2.7.11 |数据库:sqlite

更新: 序列化程序(由于我只关心多对多关系而被削减。),

class LanguageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Language
        fields = ('software_license',)

查询跟踪,

/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/response.py in rendered_content(71)
  ret = renderer.render(self.data, media_type, context)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/renderers.py in render(676)
  context = self.get_context(data, accepted_media_type, renderer_context)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/renderers.py in get_context(650)
  'put_form': self.get_rendered_html_form(data, view, 'PUT', request),
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/renderers.py in get_rendered_html_form(501)
  {'style': {'template_pack': 'rest_framework/horizontal'}}
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/renderers.py in render(359)
  return template_render(template, context)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/compat.py in template_render(241)
  return template.render(context, request=request)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/templatetags/rest_framework.py in render_field(38)
  return renderer.render_field(field, style)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/renderers.py in render_field(338)
  return template_render(template, context)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/compat.py in template_render(241)
  return template.render(context, request=request)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/utils/serializer_helpers.py in __getattr__(69)
  return getattr(self._field, attr_name)
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/relations.py in choices(493)
  return self.child_relation.choices
/home/kate/.virtualenvs/dj19/local/lib/python2.7/site-packages/rest_framework/relations.py in choices(172)
  for item in queryset

【问题讨论】:

  • @e4c5 我正在使用 restframework 序列化查询集。
  • 好吧,我不是 DRF 方面的专家。请编辑您的问题以反映您使用 DRF 的事实,并考虑更改标签以引起 DRF 专家的注意。

标签: python django django-rest-framework query-optimization django-queryset


【解决方案1】:

BrowsableAPI 经常会显示重复的查询,因为创建/更新表单会独立查询相关字段。

您可以通过将 django.db.backend 添加到您的日志记录配置并将内容类型设置为 JSON 或使用只读权限(禁用表单)来打开 Django DB 查询日志记录。

请注意,有时,Django Debug 工具栏有时会根据查询的评估方式重复查询(虽然我不记得导致它的确切条件,但我已经被这个击中了)。

【讨论】:

    【解决方案2】:

    meta.License写一个单独的序列化器

    class LicenseSerializer(serializers.ModelSerializer):
        class Meta:
            model = License
            fields = '__all__' # choose the fields you wish
    

    然后修改你的序列化器

    class LanguageSerializer(serializers.ModelSerializer):
        software_license = LicenseSerializer(many=True) # make sure you match field name
        class Meta:
            model = Language
            fields = ('software_license',)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-03
      • 2013-08-12
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      • 2020-07-13
      • 2014-09-16
      • 1970-01-01
      相关资源
      最近更新 更多