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

Django嵌套Regroup问题:属性展示与子活动显示异常

Django模板嵌套Regroup表格展示问题及优化咨询

问题描述

  1. 如何在index.html表格的对应列中展示ImplementationMatrix模型的implementation_status、implementation_summary、challenges、way_forward这4个属性,且不破坏每个ImplementationMatrix实例的布局;
  2. 模板中最后一个循环仅显示单个SubActivity,但对应Activity下存在多个子活动。

此外,希望了解更优的实现方案。


模型代码

class Strategy(TrackingModel):
    """
    Stores all the strategies related to HSSP.
    """

    strategy_name = models.CharField(
        max_length=255, blank=True, null=True, default="")

    class Meta(TrackingModel.Meta):
        verbose_name_plural = "Strategies"

    def __str__(self):
        return self.strategy_name


class Intervention(TrackingModel):
    intervention_name = models.CharField(
        max_length=255, blank=True, null=True, default=""
    )
    strategy = models.ForeignKey(Strategy, on_delete=models.PROTECT)

    class Meta(TrackingModel.Meta):
        verbose_name_plural = "Interventions"

    def __str__(self):
        return self.intervention_name


class Activity(TrackingModel):
    activity_name = models.CharField(
        max_length=255, blank=True, null=True, default="")
    intervention = models.ForeignKey(Intervention, on_delete=models.PROTECT)

    class Meta(TrackingModel.Meta):
        verbose_name_plural = "Activities"

    def __str__(self):
        return self.activity_name


class SubActivity(TrackingModel):
    subactivity_name = models.CharField(
        max_length=255, blank=True, null=True, default=""
    )
    activity = models.ForeignKey(Activity, on_delete=models.PROTECT)

    class Meta(TrackingModel.Meta):
        verbose_name_plural = "Sub Activities"

    def __str__(self):
        return self.subactivity_name


class ImplementationMatrix(TrackingModel):
    """
    The class for keeping track the implementation of each action plan
    """
    IMPLEMENTATION_STATUS = (
        ("ON PROGRESS", "ON PROGRESS"),
        ("DONE", "DONE"),
        ("NOT DONE", "NOT DONE"),
    )

    implementation_summary = models.TextField()
    implementation_status = models.CharField(
        choices=IMPLEMENTATION_STATUS, max_length=100, default="",
        verbose_name="Matrix Implementation Status"
    )
    challenges = models.TextField()
    way_forward = models.TextField()
    sub_activity = models.ForeignKey(
        SubActivity, on_delete=models.PROTECT, verbose_name='Sub-Actions')

    def __str__(self) -> str:
        return self.sub_activity.activity.intervention.strategy.strategy_name

视图代码

@login_required(login_url="/login")
def matrix_implementation_list(request: HttpRequest) -> HttpResponse:
    all_implementations = ImplementationMatrix.objects.filter(
            active=True, deleted=False).select_related(
                    'sub_activity',
                    'sub_activity__activity',
                    'sub_activity__activity__intervention',
                    'sub_activity__activity__intervention__strategy')

    context = {'all_implementations': all_implementations}
    return render(request, 'index.html', context)

模板代码(index.html)

<div class="card-body">

{% regroup all_implementations by sub_activity.activity.intervention.strategy.strategy_name as strategy_list %}

<!-- Start Table section -->
<div class="table-responsive table-bordered">
    <table class="table">
        <thead class="thead-light">
            <tr>
                <th>Policy Statement</th>
                <th>Action</th>
                <th>Sub-Actions</th>
                <th>Implementation Summary</th>
                <th>Implementation Status</th>
                <th>Challenges</th>
                <th>Way Forward</th>
            </tr>
        </thead>
        {% for strategy in strategy_list %}
        <tr>
            <td colspan="7" class="text-center"><strong>Priority Area {{ forloop.counter }}: {{ strategy.grouper }}</strong></td>
        </tr>
            {% regroup strategy.list by sub_activity.activity.intervention.intervention_name as intervention_list %}
            {% for intervention in intervention_list %}

                {% regroup intervention.list by sub_activity.activity.activity_name as activity_list %}
                {% for activity in activity_list %}

                        {% regroup activity.list by sub_activity.subactivity_name as subactivity_list %}
                        {% for subactivity in subactivity_list %}
                            <tr>
                                {% if forloop.first %}
                                    {% if forloop.parentloop.first %}
                                        <td rowspan="{{ intervention.list|length }}">
                                            {{ intervention.grouper|wordwrap:30|linebreaksbr }}
                                        </td>
                                    {% endif %}
                                        <td rowspan="{{ activity.list|length }}">
                                            {{ activity.grouper|wordwrap:30|linebreaksbr }}
                                        </td>
                                {% endif %}

                                    <td>
                                        {{ subactivity.grouper|wordwrap:20|linebreaksbr }}
                                    </td>
                                    
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                    <td></td>

                            </tr>
            {% endfor %}
        {% endfor %}
    {% endfor %}
{% endfor %}
    </table>
</div>
<!-- end Table Section -->

</div>

问题解决及优化方案

1. 展示ImplementationMatrix的属性

原模板仅渲染了SubActivity名称,未遍历对应ImplementationMatrix实例。修改最后一层循环,直接遍历每个矩阵实例并填充属性:

{% regroup activity.list by sub_activity.subactivity_name as subactivity_list %}
{% for subactivity in subactivity_list %}
    {% for matrix in subactivity.list %}
        <tr>
            {% if forloop.parentloop.first and forloop.first %}
                {% if forloop.parentloop.parentloop.first and forloop.parentloop.first %}
                    <td rowspan="{{ intervention.list|length }}">
                        {{ intervention.grouper|wordwrap:30|linebreaksbr }}
                    </td>
                {% endif %}
                <td rowspan="{{ activity.list|length }}">
                    {{ activity.grouper|wordwrap:30|linebreaksbr }}
                </td>
            {% endif %}
            {% if forloop.first %}
                <td rowspan="{{ subactivity.list|length }}">
                    {{ subactivity.grouper|wordwrap:20|linebreaksbr }}
                </td>
            {% endif %}
            
            <td>{{ matrix.implementation_summary|wordwrap:30|linebreaksbr }}</td>
            <td>{{ matrix.get_implementation_status_display }}</td>
            <td>{{ matrix.challenges|wordwrap:30|linebreaksbr }}</td>
            <td>{{ matrix.way_forward|wordwrap:30|linebreaksbr }}</td>
        </tr>
    {% endfor %}
{% endfor %}
  • 新增{% for matrix in subactivity.list %}遍历每个矩阵实例
  • 调整rowspan判断逻辑,确保父级单元格仅在第一行渲染
  • 使用get_implementation_status_display获取状态的友好文本

2. 修复SubActivity仅显示单个的问题

原问题是未遍历subactivity.list中的所有矩阵实例,上述修改已包含遍历逻辑,会自动展示SubActivity下的所有关联矩阵,同时处理一个SubActivity对应多个矩阵的多行渲染场景。

更优实现方案

方案1:视图层预分组

将分组逻辑移到视图,降低模板复杂度:

from collections import defaultdict

@login_required(login_url="/login")
def matrix_implementation_list(request: HttpRequest) -> HttpResponse:
    all_implementations = ImplementationMatrix.objects.filter(
            active=True, deleted=False).select_related(
                    'sub_activity',
                    'sub_activity__activity',
                    'sub_activity__activity__intervention',
                    'sub_activity__activity__intervention__strategy')
    
    # 预分组:Strategy -> Intervention -> Activity -> SubActivity -> ImplementationMatrix
    grouped_data = defaultdict(lambda: defaultdict(lambda: defaultdict(dict)))
    for matrix in all_implementations:
        strategy = matrix.sub_activity.activity.intervention.strategy
        intervention = matrix.sub_activity.activity.intervention
        activity = matrix.sub_activity.activity
        sub_activity = matrix.sub_activity
        
        if sub_activity.id not in grouped_data[strategy][intervention][activity]:
            grouped_data[strategy][intervention][activity][sub_activity] = []
        grouped_data[strategy][intervention][activity][sub_activity].append(matrix)
    
    context = {'grouped_data': grouped_data}
    return render(request, 'index.html', context)

模板简化循环:

{% for strategy, interventions in grouped_data.items %}
<tr>
    <td colspan="7" class="text-center"><strong>Priority Area {{ forloop.counter }}: {{ strategy.strategy_name }}</strong></td>
</tr>
{% for intervention, activities in interventions.items %}
    {% for activity, sub_activities in activities.items %}
        {% for sub_activity, matrices in sub_activities.items %}
            {% for matrix in matrices %}
            <tr>
                {% if forloop.parentloop.first and forloop.first %}
                    {% if forloop.parentloop.parentloop.first and forloop.parentloop.first %}
                    <td rowspan="{{ interventions|length }}">
                        {{ intervention.intervention_name|wordwrap:30|linebreaksbr }}
                    </td>
                    {% endif %}
                    <td rowspan="{{ activities|length }}">
                        {{ activity.activity_name|wordwrap:30|linebreaksbr }}
                    </td>
                {% endif %}
                {% if forloop.first %}
                <td rowspan="{{ matrices|length }}">
                    {{ sub_activity.subactivity_name|wordwrap:20|linebreaksbr }}
                </td>
                {% endif %}
                <td>{{ matrix.implementation_summary|wordwrap:30|linebreaksbr }}</td>
                <td>{{ matrix.get_implementation_status_display }}</td>
                <td>{{ matrix.challenges|wordwrap:30|linebreaksbr }}</td>
                <td>{{ matrix.way_forward|wordwrap:30|linebreaksbr }}</td>
            </tr>
            {% endfor %}
        {% endfor %}
    {% endfor %}
{% endfor %}
{% endfor %}

方案2:自定义模板标签

编写自定义模板标签封装分组逻辑,进一步简化模板代码,适合复杂分组场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:01:44