You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django模板/视图中高效渲染列布局组件的最优方案

高效渲染分栏组件的解决方案

方案1:使用Django内置的{% regroup %}模板标签

这是最直接的优化方式,无需大幅修改后端代码,利用Django模板原生分组能力,仅遍历一次组件列表即可完成分栏渲染,同时适配1-3列的动态布局。

后端调整

无需手动拆分多列列表,直接将排序后的widgets传入模板:

layout = Layout.objects.get(id=layout_id)
widgets = Widget.objects.prefetch_related('widgetitem','widgetitem__indicator')\
                        .filter(layouts=layout)\
                        .annotate(colno=F('layoutwidgets__widget_column'))\
                        .order_by('layoutwidgets__widget_column', 'layoutwidgets__widget_order')

context['widgets'] = widgets
return render(request,'dashboard.html', context)

模板代码

{% regroup widgets by colno as columns %}

{% for column in columns %}
    <div class="column">
        {% for widget in column.list %}
            {% include 'widget.html' %}
        {% endfor %}
    </div>
{% endfor %}

此模板会自动根据组件的colno分组渲染,无需重复编写多列循环块,遍历次数从原方案的3次降至1次,性能与可维护性均有提升。

方案2:后端用itertools.groupby高效分组

若倾向于在后端完成分组,itertools.groupby比手动循环追加列表更简洁高效——它基于已排序序列做分组,时间复杂度为O(n),不会出现你之前方案a的性能问题。

后端代码

from itertools import groupby

layout = Layout.objects.get(id=layout_id)
widgets = Widget.objects.prefetch_related('widgetitem','widgetitem__indicator')\
                        .filter(layouts=layout)\
                        .annotate(colno=F('layoutwidgets__widget_column'))\
                        .order_by('layoutwidgets__widget_column', 'layoutwidgets__widget_order')

# 按colno分组并整理为模板可用的上下文变量
columns = {}
for colno, group in groupby(widgets, key=lambda w: w.colno):
    columns[f'widgets_col{colno}'] = list(group)

context.update(columns)
return render(request,'three_column_dashboard.html', context)

模板代码

<div class="column">          
   {% for widget in widgets_col1 %}
        {% include 'widget.html' %}
   {% endfor %}    
</div>
 
<div class="column">          
   {% for widget in widgets_col2 %}
        {% include 'widget.html' %}
   {% endfor %}    
</div>

{% if widgets_col3 %}
<div class="column">          
   {% for widget in widgets_col3 %}
        {% include 'widget.html' %}
   {% endfor %}    
</div>
{% endif %}

该方案代码更简洁,且利用原生库的高效实现,避免手动循环的冗余操作。

方案3:自定义模板标签封装分组逻辑

若需在多模板复用分组逻辑,可自定义模板标签封装分组规则,让模板代码更简洁。

自定义模板标签(在app的templatetags目录下创建dashboard_tags.py)

from django import template
from itertools import groupby

register = template.Library()

@register.filter
def group_widgets_by_col(widgets):
    # 确保组件按colno排序(若后端未做排序则补充此步骤)
    sorted_widgets = sorted(widgets, key=lambda w: w.colno)
    return groupby(sorted_widgets, key=lambda w: w.colno)

模板中使用

{% load dashboard_tags %}

{% for colno, widget_group in widgets|group_widgets_by_col %}
    <div class="column">
        {% for widget in widget_group %}
            {% include 'widget.html' %}
        {% endfor %}
    </div>
{% endfor %}

此方案将分组逻辑与模板解耦,便于后续扩展或修改分组规则。

关键注意事项

  • 所有分组方案都依赖组件先按colno排序,确保分组结果正确;
  • 原方案模板多次遍历全量组件(时间复杂度O(3n)),上述方案均为O(n),虽15-20个组件的性能差异不明显,但可维护性大幅提升,后续扩展列数更便捷。

内容的提问来源于stack exchange,提问作者Craig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 14:03:23