Django 1.11中的表单渲染性能不佳

时间:2018-12-03 19:28:40

标签: html django forms python-2.7 performance

My site有一个带有高级搜索小部件的导航栏(在搜索字段旁边),该小部件在每个页面上呈现。对于每个请求,context_processor都会创建一个表单,以便可以在导航栏中的该页面上使用该表单。该表格有大约十二种选择,总共有数百种选择。这些选项大多数是针对货币和国家/地区选择的,还有大约80个其他选项。 “商店”的列表更大,但它是通过AJAX加载的,因此这里不应该考虑。

在Django 1.8上性能不错,但是在升级到1.11(Pyton 2.7.15)之后,我发现与NewRelic相比,我在以下之间的最频繁请求中使用了500毫秒以上的时间:

  • Render / django / forms / widgets / select_option.html
  • Render / django / forms / widgets / select.html
  • Render / django / forms / widgets / attrs.html

enter image description here

这似乎与1.11对Template-based Widget Renderingdocs)的更改有关,但是我只能找到有关相关问题的唯一页面是关于Django Toolbar的,而我并未在生产中运行它。

我现在已经在使用Cached Template Loader(现在是默认设置),但是我不知道这是否对您有帮助。我无法轻松地缓存此表单,因为如您在代码中所见,我根据请求设置了许多默认值。

为什么我的身体因这种变化而遭受如此严重的痛苦?消除两个较大的选择会有所帮助,但是肯定有数百个选项不应花这么长时间来渲染,因此在我看来,存在一个潜在的问题是数量只会加剧。

此处是指向完整表单和html代码的链接。 (稍后,当我们确定问题时,我将在问题中包含摘要,以供将来的读者使用。)

2 个答案:

答案 0 :(得分:1)

如果您确实将小部件渲染隔离为性能瓶颈,则可以使用其他模板为此制作自己的小部件。

class OptimizedSelectWidget(forms.Select):
    template_name = "widget_templates/optimized_select.html"

class MyForm(forms.Form):
    field = forms.ChoiceField(choices=XXX, widget=OptimizedSelectWidget)

您可以为OptimizedSelectWidget制作模板越简单,渲染速度就越快。以下是支持select小部件的全部功能的select小部件的通用(即最大复杂度)模板。我是通过采用Django 2.2下拉模板并内联所有子模板的选项来实现的。

<select name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %}
  <optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %}
  <option value="{{ option.value|stringformat:'s' }}" {% for name, value in option.attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}>{{ option.label }}</option>{% endfor %}{% if group_name %}
  </optgroup>{% endif %}{% endfor %}
</select>

我曾在一个页面上尝试过此操作,其中下拉渲染是一个性能问题,并确实获得了一定的提速,但它在20%的范围内,而不是5倍的范围。我的理论是模板缓存已经做了很多工作,因此模板本身的开销并不高。就是说,这是在Django 2.2上进行的,该版本可能在1.11之上引入了一些实质性的性能改进。

我最终解决这个问题的方法(使我的速度提高了5倍)是使用Angular将渲染下拉选项移动到浏览器。像Angular或React这样的前端框架只能用于呈现页面的一小部分。您不必重做整个前端就能做到这一点。

答案 1 :(得分:0)

在升级之前,您是否有相同请求的过去数据?如果您采用的是入门计划,则可能只有7天的数据:单击时间选择并将其设置为该日期,然后可以将过去的信息与当前的信息进行比较以找出瓶颈。