Django嵌套Regroup问题:属性展示与子活动显示异常
Django模板嵌套Regroup表格展示问题及优化咨询
问题描述
- 如何在index.html表格的对应列中展示ImplementationMatrix模型的
implementation_status、implementation_summary、challenges、way_forward这4个属性,且不破坏每个ImplementationMatrix实例的布局; - 模板中最后一个循环仅显示单个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
相关产品推荐
相关产品推荐

